Пример #1
0
        /// <summary>
        /// Function used to evaluate the length of a text string.
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public TextInfo GetTextInfo(string text)
        {
            TextInfo temp_textInfo = new TextInfo();

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

            // Early exit if string is empty.
            if (text == null || text.Length == 0)
            {
                return(null);
            }

            // Convert String to Char[]
            StringToCharArray(text, ref m_text_buffer);

            int size = GetArraySizes(m_text_buffer);

            temp_textInfo.characterInfo = new TMPro_CharacterInfo[size];


            m_fontIndex = 0;
            m_fontAssetArray[m_fontIndex] = m_fontAsset;
            // Scale the font to approximately match the point size
            m_fontScale = (m_fontSize / m_fontAssetArray[m_fontIndex].fontInfo.PointSize * (m_isOrthographic ? 1 : 0.1f));
            float baseScale = m_fontScale; // BaseScale keeps the character aligned vertically since <size=+000> results in font of different scale.

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

            //bool isMissingCharacter; // Used to handle missing characters in the Font Atlas / Definition.

            m_style = FontStyles.Normal; // Set defaul style as normal.

            // GetPadding to adjust the size of the mesh due to border thickness, softness, glow, etc...
            if (checkPaddingRequired)
            {
                checkPaddingRequired = false;
                m_padding            = ShaderUtilities.GetPadding(m_renderer.sharedMaterials, m_enableExtraPadding, m_isUsingBold);
                m_alignmentPadding   = ShaderUtilities.GetFontExtent(m_sharedMaterial);
            }

            float style_padding       = 0; // Extra padding required to accomodate Bold style.
            float xadvance_multiplier = 1; // Used to increase spacing between character when style is bold.

            m_baselineOffset = 0;          // Used by subscript characters.

            float lineOffset = 0;          // Amount of space between lines (font line spacing + m_linespacing).

            m_xAdvance = 0;                // Used to track the position of each character.

            int lineNumber             = 0;
            int wordCount              = 0;
            int character_Count        = 0; // Total characters in the char[]
            int visibleCharacter_Count = 0; // # of visible characters.

            // Limit Line Length to whatever size fits all characters on a single line.
            m_lineLength = m_lineLength > max_LineWrapLength ? max_LineWrapLength : m_lineLength;

            // Initialize struct to track states of word wrapping
            m_SaveWordWrapState = new WordWrapState();
            int wrappingIndex = 0;


            if (temp_textInfo.lineInfo == null)
            {
                temp_textInfo.lineInfo = new LineInfo[8];
            }
            for (int i = 0; i < temp_textInfo.lineInfo.Length; i++)
            {
                temp_textInfo.lineInfo[i] = new LineInfo();
                //m_textInfo.lineInfo[i].lineExtents = new Extents(k_InfinityVector, -k_InfinityVector);
            }


            // Tracking of the highest Ascender
            float maxAscender  = 0;
            float maxDescender = 0;

            int lastLineNumber = 0;

            int endTagIndex = 0;

            // Parse through Character buffer to read html tags and begin creating mesh.
            for (int i = 0; m_text_buffer[i] != 0; i++)
            {
                m_tabSpacing = -999;
                m_spacing    = -999;
                charCode     = m_text_buffer[i];

                if (m_isRichText && charCode == 60)  // '<'
                {
                    // Check if Tag is valid. If valid, skip to the end of the validated tag.
                    if (ValidateHtmlTag(m_text_buffer, i + 1, out endTagIndex))
                    {
                        i = endTagIndex;
                        if (m_tabSpacing != -999)
                        {
                            // Move character to a fix position. Position expresses in characters (approximation).
                            m_xAdvance = m_tabSpacing * m_cached_Underline_GlyphInfo.width * m_fontScale;
                        }

                        if (m_spacing != -999)
                        {
                            m_xAdvance += m_spacing * m_fontScale * m_cached_Underline_GlyphInfo.width;
                        }

                        continue;
                    }
                }

                //isMissingCharacter = false;

                // Look up Character Data from Dictionary and cache it.
                m_fontAssetArray[m_fontIndex].characterDictionary.TryGetValue(charCode, out m_cached_GlyphInfo);
                if (m_cached_GlyphInfo == null)
                {
                    // Character wasn't found in the Dictionary.
                    m_fontAssetArray[m_fontIndex].characterDictionary.TryGetValue(88, out m_cached_GlyphInfo);
                    if (m_cached_GlyphInfo != null)
                    {
                        Debug.LogWarning("Character with ASCII value of " + charCode + " was not found in the Font Asset Glyph Table.");
                        // Replace the missing character by X (if it is found)
                        charCode = 88;
                        //isMissingCharacter = true;
                    }
                    else
                    {  // At this point the character isn't in the Dictionary, the replacement X isn't either so ...
                       //continue;
                    }
                }


                // Store some of the text object's information
                temp_textInfo.characterInfo[character_Count].character = (char)charCode;
                //temp_textInfo.characterInfo[character_Count].color = m_htmlColor;
                //temp_textInfo.characterInfo[character_Count].style = m_style;
                temp_textInfo.characterInfo[character_Count].index = (short)i;


                // Handle Kerning if Enabled.
                if (m_enableKerning && character_Count >= 1)
                {
                    KerningPairKey keyValue = new KerningPairKey(prev_charCode, charCode);

                    KerningPair pair;

                    m_fontAsset.kerningDictionary.TryGetValue(keyValue.key, out pair);
                    if (pair != null)
                    {
                        m_xAdvance += pair.XadvanceOffset * m_fontScale;
                    }
                }



                // Set Padding based on selected font style
                if ((m_style & FontStyles.Bold) == FontStyles.Bold) // Checks for any combination of Bold Style.
                {
                    style_padding       = m_fontAsset.BoldStyle * 2;
                    xadvance_multiplier = 1.07f; // Increase xAdvance for bold characters.
                }
                else
                {
                    style_padding       = m_fontAsset.NormalStyle * 2;
                    xadvance_multiplier = 1.0f;
                }


                // Setup Vertices for each character.
                Vector3 top_left     = new Vector3(0 + m_xAdvance + ((m_cached_GlyphInfo.xOffset - m_padding - style_padding) * m_fontScale), (m_cached_GlyphInfo.yOffset + m_baselineOffset + m_padding) * m_fontScale - lineOffset * baseScale, 0);
                Vector3 bottom_left  = new Vector3(top_left.x, top_left.y - ((m_cached_GlyphInfo.height + m_padding * 2) * m_fontScale), 0);
                Vector3 top_right    = new Vector3(bottom_left.x + ((m_cached_GlyphInfo.width + m_padding * 2 + style_padding * 2) * m_fontScale), top_left.y, 0);
                Vector3 bottom_right = new Vector3(top_right.x, bottom_left.y, 0);


                // Check if we need to Shear the rectangles for Italic styles
                if ((m_style & FontStyles.Italic) == FontStyles.Italic)
                {
                    // Shift Top vertices forward by half (Shear Value * height of character) and Bottom vertices back by same amount.
                    float   shear_value = m_fontAsset.ItalicStyle * 0.01f;
                    Vector3 topShear    = new Vector3(shear_value * ((m_cached_GlyphInfo.yOffset + m_padding + style_padding) * m_fontScale), 0, 0);
                    Vector3 bottomShear = new Vector3(shear_value * (((m_cached_GlyphInfo.yOffset - m_cached_GlyphInfo.height - m_padding - style_padding)) * m_fontScale), 0, 0);

                    top_left     = top_left + topShear;
                    bottom_left  = bottom_left + bottomShear;
                    top_right    = top_right + topShear;
                    bottom_right = bottom_right + bottomShear;
                }


                // Track Word Count per line and for the object
                if (character_Count > 0 && (char.IsWhiteSpace((char)charCode) || char.IsPunctuation((char)charCode)))
                {
                    if (char.IsLetterOrDigit(temp_textInfo.characterInfo[character_Count - 1].character))
                    {
                        wordCount += 1;
                        temp_textInfo.lineInfo[lineNumber].wordCount += 1;
                    }
                }


                // Setup Mesh for visible characters. ie. not a SPACE / LINEFEED / CARRIAGE RETURN.
                if (charCode != 32 && charCode != 9 && charCode != 10 && charCode != 13)
                {
                    // Determine the bounds of the Mesh.
                    //meshExtents.min = new Vector2(Mathf.Min(meshExtents.min.x, bottom_left.x), Mathf.Min(meshExtents.min.y, bottom_left.y));
                    //meshExtents.max = new Vector2(Mathf.Max(meshExtents.max.x, top_right.x), Mathf.Max(meshExtents.max.y, top_left.y));

                    // Determine the extend of each line
                    LineInfo lineInfo    = temp_textInfo.lineInfo[lineNumber];
                    Extents  lineExtents = lineInfo.lineExtents;
                    temp_textInfo.lineInfo[lineNumber].lineExtents.min = new Vector2(Mathf.Min(lineExtents.min.x, bottom_left.x), Mathf.Min(lineExtents.min.y, bottom_left.y));
                    temp_textInfo.lineInfo[lineNumber].lineExtents.max = new Vector2(Mathf.Max(lineExtents.max.x, top_right.x), Mathf.Max(lineExtents.max.y, top_left.y));


                    if (m_enableWordWrapping && top_right.x > m_lineLength)
                    {
                        // Check if further wrapping is possible or if we need to increase the line length
                        if (wrappingIndex == m_SaveWordWrapState.previous_WordBreak)
                        {
                            if (isAffectingWordWrapping)
                            {
                                m_lineLength = Mathf.Round(top_right.x * 100 + 0.5f) / 100f;//m_lineLength = top_right.x;
                                GenerateTextMesh();
                                isAffectingWordWrapping = false;
                            }

                            Debug.Log("Line " + lineNumber + " Cannot wrap lines anymore.");
                            return(null);
                        }

                        // Restore to previously stored state
                        character_Count                 = m_SaveWordWrapState.total_CharacterCount + 1;
                        visibleCharacter_Count          = m_SaveWordWrapState.visible_CharacterCount;
                        m_textInfo.lineInfo[lineNumber] = m_SaveWordWrapState.lineInfo;

                        m_htmlColor      = m_SaveWordWrapState.vertexColor;
                        m_style          = m_SaveWordWrapState.fontStyle;
                        m_baselineOffset = m_SaveWordWrapState.baselineOffset;
                        m_fontScale      = m_SaveWordWrapState.fontScale;
                        i             = m_SaveWordWrapState.previous_WordBreak;
                        wrappingIndex = i;  // Used to dectect when line length can no longer be reduced.

                        lineNumber += 1;
                        // Check to make sure Array is large enough to hold a new line.
                        if (lineNumber >= temp_textInfo.lineInfo.Length)
                        {
                            Array.Resize(ref temp_textInfo.lineInfo, Mathf.NextPowerOfTwo(lineNumber));
                        }


                        lineOffset += (m_fontAssetArray[m_fontIndex].fontInfo.LineHeight + m_lineSpacing);
                        m_xAdvance  = 0;
                        continue;
                    }

                    //visibleCharacter_Count += 1;
                }
                else
                {   // This is a Space, Tab, LineFeed or Carriage Return
                    // Track # of spaces per line which is used for line justification.
                    if (charCode == 9 || charCode == 32)
                    {
                        //m_lineExtents[lineNumber].spaceCount += 1;
                        temp_textInfo.lineInfo[lineNumber].spaceCount += 1;
                        temp_textInfo.spaceCount += 1;
                    }

                    // 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.
                    m_SaveWordWrapState.previous_WordBreak     = i;
                    m_SaveWordWrapState.total_CharacterCount   = character_Count;
                    m_SaveWordWrapState.visible_CharacterCount = visibleCharacter_Count;
                    m_SaveWordWrapState.maxLineLength          = m_xAdvance;
                    m_SaveWordWrapState.fontScale      = m_fontScale;
                    m_SaveWordWrapState.baselineOffset = m_baselineOffset;
                    m_SaveWordWrapState.fontStyle      = m_style;
                    m_SaveWordWrapState.vertexColor    = m_htmlColor;
                    m_SaveWordWrapState.lineInfo       = temp_textInfo.lineInfo[lineNumber];
                }


                // Store Rectangle positions for each Character.
                temp_textInfo.characterInfo[character_Count].bottomLeft = bottom_left;
                temp_textInfo.characterInfo[character_Count].topRight   = top_right;
                temp_textInfo.characterInfo[character_Count].lineNumber = (short)lineNumber;

                //temp_textInfo.characterInfo[character_Count].baseLine = top_right.y - (m_cached_GlyphInfo.yOffset + m_padding) * m_fontScale;
                //temp_textInfo.characterInfo[character_Count].topLine = temp_textInfo.characterInfo[character_Count].baseLine + (m_fontAssetArray[m_fontIndex].fontInfo.Ascender + m_alignmentPadding.y) * m_fontScale; // Ascender
                //temp_textInfo.characterInfo[character_Count].bottomLine = temp_textInfo.characterInfo[character_Count].baseLine + (m_fontAssetArray[m_fontIndex].fontInfo.Descender - m_alignmentPadding.w) * m_fontScale; // Descender

                maxAscender  = temp_textInfo.characterInfo[character_Count].topLine > maxAscender ? temp_textInfo.characterInfo[character_Count].topLine : maxAscender;
                maxDescender = temp_textInfo.characterInfo[character_Count].bottomLine < maxDescender ? temp_textInfo.characterInfo[character_Count].bottomLine : maxDescender;

                //temp_textInfo.characterInfo[character_Count].aspectRatio = m_cached_GlyphInfo.width / m_cached_GlyphInfo.height;
                //temp_textInfo.characterInfo[character_Count].scale = m_fontScale;
                temp_textInfo.lineInfo[lineNumber].characterCount += 1;

                //Debug.Log("Character #" + i + " is [" + (char)charCode + "] ASCII (" + charCode + ")");

                // Store LineInfo
                if (lineNumber != lastLineNumber)
                {
                    temp_textInfo.lineInfo[lineNumber].firstCharacterIndex    = character_Count;
                    temp_textInfo.lineInfo[lineNumber - 1].lastCharacterIndex = character_Count - 1;
                    temp_textInfo.lineInfo[lineNumber - 1].characterCount     = temp_textInfo.lineInfo[lineNumber - 1].lastCharacterIndex - temp_textInfo.lineInfo[lineNumber - 1].firstCharacterIndex + 1;
                    temp_textInfo.lineInfo[lineNumber - 1].lineLength         = temp_textInfo.characterInfo[character_Count - 1].topRight.x - m_padding * m_fontScale;
                }



                lastLineNumber = lineNumber;

                // Handle Tabulation Stops. Tab stops at every 25% of Font Size.
                if (charCode == 9)
                {
                    m_xAdvance = (int)(m_xAdvance / (m_fontSize * 0.25f) + 1) * (m_fontSize * 0.25f);
                }
                else
                {
                    m_xAdvance += (m_cached_GlyphInfo.xAdvance * xadvance_multiplier * m_fontScale) + m_characterSpacing;
                }


                // Handle Line Feed as well as Word Wrapping
                if (charCode == 10 || charCode == 13)
                {
                    lineNumber += 1;

                    // Check to make sure Array is large enough to hold a new line.
                    if (lineNumber >= temp_textInfo.lineInfo.Length)
                    {
                        Array.Resize(ref temp_textInfo.lineInfo, Mathf.NextPowerOfTwo(lineNumber));
                    }


                    lineOffset += (m_fontAssetArray[m_fontIndex].fontInfo.LineHeight + m_lineSpacing);
                    m_xAdvance  = 0;
                }

                character_Count += 1;
                prev_charCode    = charCode;
            }


            temp_textInfo.lineInfo[lineNumber].lastCharacterIndex = character_Count - 1;
            temp_textInfo.lineInfo[lineNumber].characterCount     = temp_textInfo.lineInfo[lineNumber].lastCharacterIndex - temp_textInfo.lineInfo[lineNumber].firstCharacterIndex + 1;
            temp_textInfo.lineInfo[lineNumber].lineLength         = temp_textInfo.characterInfo[character_Count - 1].topRight.x - m_padding * m_fontScale;

            //m_textMetrics = new TMPro_TextMetrics();
            temp_textInfo.characterCount = character_Count;
            temp_textInfo.lineCount      = lineNumber + 1;
            temp_textInfo.wordCount      = wordCount;

            //for (int i = 0; i < lineNumber + 1; i++)
            //{
            //    Debug.Log("Line: " + (i + 1) + "  # Char: " + temp_textInfo.lineInfo[i].characterCount
            //                                 + "  Word Count: " + temp_textInfo.lineInfo[i].wordCount
            //                                 + "  Space: " + temp_textInfo.lineInfo[i].spaceCount
            //                                 + "  First:" + temp_textInfo.lineInfo[i].firstCharacterIndex + "  Last [" + temp_textInfo.characterInfo[temp_textInfo.lineInfo[i].lastCharacterIndex].character
            //                                 + "] at Index: " + temp_textInfo.lineInfo[i].lastCharacterIndex + "  Length: " + temp_textInfo.lineInfo[i].lineLength
            //                                 + " Line Extents: " + temp_textInfo.lineInfo[i].lineExtents);

            //    //Debug.Log("line: " + (i + 1) + "  m_lineExtents Count: " + m_lineExtents[i].characterCount + "  lineInfo: " + m_textInfo.lineInfo[i].characterCount);
            //    //Debug.DrawLine(new Vector3(m_textInfo.lineInfo[i].lineLength, 2, 0), new Vector3(m_textInfo.lineInfo[i].lineLength, -2, 0), Color.red, 30f);
            //}

            return(temp_textInfo);
        }
        // Function to increase the size of the Line Extents Array.
        void ResizeLineExtents(int size)
        {
            size = size > 1024 ? size + 256 : Mathf.NextPowerOfTwo(size + 1);

            LineInfo[] temp_lineInfo = new LineInfo[size];
            for (int i = 0; i < size; i++)
            {
                if (i < m_textInfo.lineInfo.Length)
                    temp_lineInfo[i] = m_textInfo.lineInfo[i];
                else
                {
                    temp_lineInfo[i].lineExtents = new Extents(k_InfinityVector, -k_InfinityVector);
                    temp_lineInfo[i].ascender = -k_InfinityVector.x;
                    temp_lineInfo[i].descender = k_InfinityVector.x;
                }
            }

            m_textInfo.lineInfo = temp_lineInfo;
        }
Пример #3
0
 // Function to increase the size of the Line Extents Array.
 void ResizeLineExtents(int size)
 {
     size = size > 1024 ? size + 256 : Mathf.NextPowerOfTwo(size + 1);
    
     LineInfo[] temp_lineInfo = new LineInfo[size];
     for (int i = 0; i < m_textInfo.lineInfo.Length; i++)                         
         temp_lineInfo[i] = m_textInfo.lineInfo[i];
             
     m_textInfo.lineInfo = temp_lineInfo;
 }