美文网首页
FairyGUI对TextMeshPro的fallback fo

FairyGUI对TextMeshPro的fallback fo

作者: 不正经的搬砖工 | 来源:发表于2022-03-04 11:12 被阅读0次

    最近项目中某些文字效果,使用TextMeshPro能更好、更快速的实现,看FairyGUI对TextMeshPro也有了支持,就决定使用了。项目中涉及多语言,但给的字体库不支持中文,只能使用备用字体库,看TMP中有个Fallback Font Assets(如图1-1),以为就可以这么愉快的搞定了,奈何FairyGUI并不支持这个特性,求助FairyGUI官网群也无果,只能自己解决了。

    图 1-1 Fallback Font Assets

    看了一下UGUI中对这一特性的支持,它就是额外创建了一个TMP_SubMeshUI使用备用字体绘制文本。

    图 1-2 UGUI中对TMP Fallback的支持 

    (1)参照这个思路,在FairyGUI中创建一个GSubTextField使用备用字体绘制文本,GSubTextField基本上就是GTextField的拷贝,只是对Setup_BeforeAdd做了一些改动,当创建GSubTextField时,完全用GTextField的各种属性设置GSubTextField。由于TMP_FontAsset中的fallbackFontAssets为私有属性无法访问,我直接在GSubTextField中手动设置了备用字体。代码如下:

    public void Setup_BeforeAdd(TextFormat ptf, GTextField gtf)

            {

                SetXY(gtf.x, gtf.y);

                SetSize(gtf.width, gtf.height, true);

                minWidth = gtf.minWidth;

                maxWidth = gtf.maxWidth;

                minHeight = gtf.minHeight;

                maxHeight = gtf.maxHeight;

                SetScale(gtf.scaleX, gtf.scaleY);

                this.skew = gtf.skew;

                SetPivot(gtf.pivot.x, gtf.pivot.y, gtf.pivotAsAnchor);

                this.alpha = gtf.alpha;

                this.rotation = gtf.rotation;

                this.visible = gtf.visible;

                this.touchable = false;

                this.grayed = gtf.grayed;

                this.blendMode = gtf.blendMode;

                TextFormat tf = _textField.textFormat;

                tf.font = UIConfig.defaultFont;

                tf.size = ptf.size;

                tf.color = ptf.color;

                this.align = gtf.align;

                this.verticalAlign = gtf.verticalAlign;

                tf.lineSpacing = ptf.lineSpacing;

                tf.letterSpacing = ptf.letterSpacing;

                _ubbEnabled = gtf.UBBEnabled;

                this.autoSize = gtf.autoSize;

                tf.underline = ptf.underline;

                tf.italic = ptf.italic;

                tf.bold = ptf.bold;

                this.singleLine = gtf.singleLine;

                tf.outlineColor = ptf.outlineColor;

                tf.outline = ptf.outline;

                tf.shadowColor = ptf.shadowColor;

                tf.shadowOffset = new Vector2(ptf.shadowOffset.x, ptf.shadowOffset.y);

                if(gtf.templateVars != null)

                    _templateVars = new Dictionary<string, string>();

                tf.strikethrough = ptf.strikethrough;

                tf.faceDilate = ptf.faceDilate;

                tf.outlineSoftness = ptf.outlineSoftness;

                tf.underlaySoftness = ptf.underlaySoftness;

                _textField.textFormat = tf;

                SetUnderlayDilate(ptf.underlayDilate);

            }

    (2)GTextField中实现创建GSubTextField的接口和刷新文字的接口:如下所示:

    #if FAIRYGUI_TMPRO

            public void CreateSubTextField()

            {

                if (_subGTextField == null)

                {

                    _subGTextField = new GSubTextField();

                    _subGTextField.Setup_BeforeAdd(_textField.textFormat, this);

                    _subGTextField.relations.CopyFrom(this.relations);

                    if (parent!=null)

                    {

                        parent.AddChild(_subGTextField);

                    }

                }

            }

            public void RefreshSubText()

            {

                if (_subGTextField != null)

                {

                    if (_text.Equals(_subGTextField.text) == false)

                    {

                        _subGTextField.text = _text;

                    }

                }

            }

    #endif

    (3)FairyGUI中每次修改文本时都会调用TextField中的BuildLines2()重新构建字符,我们在这个接口中根据文本需不需要备用字体来决定是否需要创建GSubTextField及刷不刷新GSubTextField的文本,实现如下:

    void BuildLines2()

            {

                float letterSpacing = _textFormat.letterSpacing * _fontSizeScale;

                float lineSpacing = (_textFormat.lineSpacing - 1) * _fontSizeScale;

                float rectWidth = _contentRect.width - GUTTER_X * 2;

                float glyphWidth = 0, glyphHeight = 0, baseline = 0;

    #if FAIRYGUI_TMPRO

                bool isFallback;

                bool fallback = false;

    #endif

                short wordLen = 0;

                bool wordPossible = false;

                float posx = 0;

                TextFormat format = _textFormat;

                _font.SetFormat(format, _fontSizeScale);

                bool wrap = _wordWrap && !_singleLine;

                if (_maxWidth > 0)

                {

                    wrap = true;

                    rectWidth = _maxWidth - GUTTER_X * 2;

                }

                _textWidth = _textHeight = 0;

                RequestText();

                int elementCount = _elements.Count;

                int elementIndex = 0;

                HtmlElement element = null;

                if (elementCount > 0)

                    element = _elements[elementIndex];

                int textLength = _parsedText.Length;

                LineInfo line = LineInfo.Borrow();

                _lines.Add(line);

                line.y = line.y2 = GUTTER_Y;

                sLineChars.Clear();

                for (int charIndex = 0; charIndex < textLength; charIndex++)

                {

                    char ch = _parsedText[charIndex];

                    glyphWidth = glyphHeight = baseline = 0;

                    while (element != null && element.charIndex == charIndex)

                    {

                        if (element.type == HtmlElementType.Text)

                        {

                            format = element.format;

                            _font.SetFormat(format, _fontSizeScale);

                        }

                        else

                        {

                            IHtmlObject htmlObject = element.htmlObject;

                            if (_richTextField != null && htmlObject == null)

                            {

                                element.space = (int)(rectWidth - line.width - 4);

                                htmlObject = _richTextField.htmlPageContext.CreateObject(_richTextField, element);

                                element.htmlObject = htmlObject;

                            }

                            if (htmlObject != null)

                            {

                                glyphWidth = htmlObject.width + 2;

                                glyphHeight = htmlObject.height;

                                baseline = glyphHeight * IMAGE_BASELINE;

                            }

                            if (element.isEntity)

                                ch = '\0'; //indicate it is a place holder

                        }

                        elementIndex++;

                        if (elementIndex < elementCount)

                            element = _elements[elementIndex];

                        else

                            element = null;

                    }

                    if (ch == '\0' || ch == '\n')

                    {

                        wordPossible = false;

                    }

    #if FAIRYGUI_TMPRO

                    else if (_font.GetGlyphWithFallback(ch == '\t' ? ' ' : ch, out glyphWidth, out glyphHeight, out baseline,out isFallback))

                    {

                        if ((isFallback == true)&&(this.gOwner!=null))

                        {

                            if(this.gOwner.GetType()==typeof(GTextField))

                            {

                                fallback = true;

                                if(isFirst == true)

                                {

                                    isFirst = false;

                                    ((GTextField)gOwner).CreateSubTextField();

                                }

                            }

                        }

    #else

                    else if (_font.GetGlyph(ch == '\t' ? ' ' : ch, out glyphWidth, out glyphHeight, out baseline))

                    {

    #endif

                        if (ch == '\t')

                            glyphWidth *= 4;

                        if (wordPossible)

                        {

                            if (char.IsWhiteSpace(ch))

                            {

                                wordLen = 0;

                            }

                            else if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z'

                                || ch >= '0' && ch <= '9'

                                || ch == '.' || ch == '"' || ch == '\''

                                || format.specialStyle == TextFormat.SpecialStyle.Subscript

                                || format.specialStyle == TextFormat.SpecialStyle.Superscript

                                || _textDirection != RTLSupport.DirectionType.UNKNOW && RTLSupport.IsArabicLetter(ch))

                            {

                                wordLen++;

                            }

                            else

                                wordPossible = false;

                        }

                        else if (char.IsWhiteSpace(ch))

                        {

                            wordLen = 0;

                            wordPossible = true;

                        }

                        else if (format.specialStyle == TextFormat.SpecialStyle.Subscript

                            || format.specialStyle == TextFormat.SpecialStyle.Superscript)

                        {

                            if (sLineChars.Count > 0)

                            {

                                wordLen = 2; //避免上标和下标折到下一行

                                wordPossible = true;

                            }

                        }

                        else

                            wordPossible = false;

                    }

                    else

                        wordPossible = false;

                    sLineChars.Add(new LineCharInfo() { width = glyphWidth, height = glyphHeight, baseline = baseline });

                    if (glyphWidth != 0)

                    {

                        if (posx != 0)

                            posx += letterSpacing;

                        posx += glyphWidth;

                    }

                    if (ch == '\n' && !_singleLine)

                    {

                        UpdateLineInfo(line, letterSpacing, sLineChars.Count);

                        LineInfo newLine = LineInfo.Borrow();

                        _lines.Add(newLine);

                        newLine.y = line.y + (line.height + lineSpacing);

                        if (newLine.y < GUTTER_Y) //lineSpacing maybe negative

                            newLine.y = GUTTER_Y;

                        newLine.y2 = newLine.y;

                        newLine.charIndex = line.charIndex + line.charCount;

                        sLineChars.Clear();

                        wordPossible = false;

                        posx = 0;

                        line = newLine;

                    }

                    else if (wrap && posx > rectWidth)

                    {

                        int lineCharCount = sLineChars.Count;

                        int toMoveChars;

                        if (wordPossible && wordLen < 20 && lineCharCount > 2) //if word had broken, move word to new line

                        {

                            toMoveChars = wordLen;

                            //we caculate the line width WITHOUT the tailing space

                            UpdateLineInfo(line, letterSpacing, lineCharCount - (toMoveChars + 1));

                            line.charCount++; //but keep it in this line.

                        }

                        else

                        {

                            toMoveChars = lineCharCount > 1 ? 1 : 0; //if only one char here, we cant move it to new line

                            UpdateLineInfo(line, letterSpacing, lineCharCount - toMoveChars);

                        }

                        LineInfo newLine = LineInfo.Borrow();

                        _lines.Add(newLine);

                        newLine.y = line.y + (line.height + lineSpacing);

                        if (newLine.y < GUTTER_Y)

                            newLine.y = GUTTER_Y;

                        newLine.y2 = newLine.y;

                        newLine.charIndex = line.charIndex + line.charCount;

                        posx = 0;

                        if (toMoveChars != 0)

                        {

                            for (int i = line.charCount; i < lineCharCount; i++)

                            {

                                LineCharInfo ci = sLineChars[i];

                                if (posx != 0)

                                    posx += letterSpacing;

                                posx += ci.width;

                            }

                            sLineChars.RemoveRange(0, line.charCount);

                        }

                        else

                            sLineChars.Clear();

                        wordPossible = false;

                        line = newLine;

                    }

                }

                UpdateLineInfo(line, letterSpacing, sLineChars.Count);

                if (_textWidth > 0)

                    _textWidth += GUTTER_X * 2;

                _textHeight = line.y + line.height + GUTTER_Y;

                _textWidth = Mathf.RoundToInt(_textWidth);

                _textHeight = Mathf.RoundToInt(_textHeight);

    #if FAIRYGUI_TMPRO

                if ((fallback==true)||(fallback != lastNeedFallback))

                {

                    lastNeedFallback = fallback;

                    ((GTextField)gOwner).RefreshSubText();

                }

    #endif

            }

    另外在TMPFont中添加了一个接口以便判断文本是否需要备用字体,实现如下:

    override public bool GetGlyphWithFallback(char ch, out float width, out float height, out float baseline,out bool isFallback)

            {

                isFallback = false;

                _char = GetCharacterFromFontAssetWithoutFallback(ch, _style);

                if (_char == null)

                {

                    _char = GetCharacterFromFontAsset(ch, _style);

                    if(_char != null)

                    {

                        isFallback = true;

                    }   

                }

                if(_char != null)

                {

                    width = _char.glyph.metrics.horizontalAdvance * _boldMultiplier * _scale;

                    height = _lineHeight * _scale;

                    baseline = _ascent * _scale;

                    if (_format.specialStyle == TextFormat.SpecialStyle.Subscript)

                    {

                        height /= SupScale;

                        baseline /= SupScale;

                    }

                    else if (_format.specialStyle == TextFormat.SpecialStyle.Superscript)

                    {

                        height = height / SupScale + baseline * SupOffset;

                        baseline *= (SupOffset + 1 / SupScale);

                    }

                    height = Mathf.RoundToInt(height);

                    baseline = Mathf.RoundToInt(baseline);

                    return true;

                }

                width = 0;

                height = 0;

                baseline = 0;

                return false;

            }

            TMP_Character GetCharacterFromFontAssetWithoutFallback(uint unicode, FontStyles fontStyle)

            {

                bool isAlternativeTypeface;

    #pragma warning disable

                TMP_FontAsset actualAsset;

    #pragma warning restore

                return TMP_FontAssetUtilities.GetCharacterFromFontAsset(unicode, _fontAsset, false, fontStyle, _fontWeight,

                    out isAlternativeTypeface

                //,out actualAsset //old TMP version need this line

                );

            }

    (4)最后修改textField中的OnPopulateMesh,根据字符是否在当前字体中决定是否绘制字形用于渲染,修改如下:

    public void OnPopulateMesh(VertexBuffer vb)

            {

                if (_textWidth == 0 && _lines.Count == 1)

                {

                    if (_charPositions != null)

                    {

                        _charPositions.Clear();

                        _charPositions.Add(new CharPosition());

                    }

                    if (_richTextField != null)

                        _richTextField.RefreshObjects();

                    return;

                }

                float letterSpacing = _textFormat.letterSpacing * _fontSizeScale;

                TextFormat format = _textFormat;

                _font.SetFormat(format, _fontSizeScale);

                _font.UpdateGraphics(graphics);

                float rectWidth = _contentRect.width > 0 ? (_contentRect.width - GUTTER_X * 2) : 0;

                float rectHeight = _contentRect.height > 0 ? Mathf.Max(_contentRect.height, _font.GetLineHeight(format.size)) : 0;

                if (_charPositions != null)

                    _charPositions.Clear();

                List<Vector3> vertList = vb.vertices;

                List<Vector2> uvList = vb.uvs;

                List<Vector2> uv2List = vb.uvs2;

                List<Color32> colList = vb.colors;

                HtmlLink currentLink = null;

                float linkStartX = 0;

                int linkStartLine = 0;

                float posx = 0;

                float indent_x;

                bool clipping = !_input && _autoSize == AutoSizeType.None;

                bool lineClipped;

                AlignType lineAlign;

                float glyphWidth, glyphHeight, baseline;

                bool isFallback;

                short vertCount;

                float underlineStart;

                float strikethroughStart;

                int minFontSize;

                int maxFontSize;

                string rtlLine = null;

                int elementIndex = 0;

                int elementCount = _elements.Count;

                HtmlElement element = null;

                if (elementCount > 0)

                    element = _elements[elementIndex];

                int lineCount = _lines.Count;

                for (int i = 0; i < lineCount; ++i)

                {

                    LineInfo line = _lines[i];

                    if (line.charCount == 0)

                        continue;

                    lineClipped = clipping && i != 0 && line.y + line.height > rectHeight;

                    lineAlign = format.align;

                    if (element != null && element.charIndex == line.charIndex)

                        lineAlign = element.format.align;

                    else

                        lineAlign = format.align;

                    if (_textDirection == RTLSupport.DirectionType.RTL)

                    {

                        if (lineAlign == AlignType.Center)

                            indent_x = (int)((rectWidth + line.width) / 2);

                        else if (lineAlign == AlignType.Right)

                            indent_x = rectWidth;

                        else

                            indent_x = line.width + GUTTER_X * 2;

                        if (indent_x > rectWidth)

                            indent_x = rectWidth;

                        posx = indent_x - GUTTER_X;

                    }

                    else

                    {

                        if (lineAlign == AlignType.Center)

                            indent_x = (int)((rectWidth - line.width) / 2);

                        else if (lineAlign == AlignType.Right)

                            indent_x = rectWidth - line.width;

                        else

                            indent_x = 0;

                        if (indent_x < 0)

                            indent_x = 0;

                        posx = GUTTER_X + indent_x;

                    }

                    int lineCharCount = line.charCount;

                    underlineStart = posx;

                    strikethroughStart = posx;

                    minFontSize = maxFontSize = format.size;

                    if (_textDirection != RTLSupport.DirectionType.UNKNOW)

                    {

                        rtlLine = _parsedText.Substring(line.charIndex, lineCharCount);

                        if (_textDirection == RTLSupport.DirectionType.RTL)

                            rtlLine = RTLSupport.ConvertLineR(rtlLine);

                        else

                            rtlLine = RTLSupport.ConvertLineL(rtlLine);

                        lineCharCount = rtlLine.Length;

                    }

                    for (int j = 0; j < lineCharCount; j++)

                    {

                        int charIndex = line.charIndex + j;

                        char ch = rtlLine != null ? rtlLine[j] : _parsedText[charIndex];

                        while (element != null && charIndex == element.charIndex)

                        {

                            if (element.type == HtmlElementType.Text)

                            {

                                vertCount = 0;

                                if (format.underline != element.format.underline)

                                {

                                    if (format.underline)

                                    {

                                        if (!lineClipped)

                                        {

                                            float lineWidth;

                                            if (_textDirection == RTLSupport.DirectionType.UNKNOW)

                                                lineWidth = (clipping ? Mathf.Clamp(posx, GUTTER_X, GUTTER_X + rectWidth) : posx) - underlineStart;

                                            else

                                                lineWidth = underlineStart - (clipping ? Mathf.Clamp(posx, GUTTER_X, GUTTER_X + rectWidth) : posx);

                                            if (lineWidth > 0)

                                                vertCount += (short)_font.DrawLine(underlineStart < posx ? underlineStart : posx, -(line.y + line.baseline), lineWidth,

                                                    maxFontSize, 0, vertList, uvList, uv2List, colList);

                                        }

                                        maxFontSize = 0;

                                    }

                                    else

                                        underlineStart = posx;

                                }

                                if (format.strikethrough != element.format.strikethrough)

                                {

                                    if (format.strikethrough)

                                    {

                                        if (!lineClipped)

                                        {

                                            float lineWidth;

                                            if (_textDirection == RTLSupport.DirectionType.UNKNOW)

                                                lineWidth = (clipping ? Mathf.Clamp(posx, GUTTER_X, GUTTER_X + rectWidth) : posx) - strikethroughStart;

                                            else

                                                lineWidth = strikethroughStart - (clipping ? Mathf.Clamp(posx, GUTTER_X, GUTTER_X + rectWidth) : posx);

                                            if (lineWidth > 0)

                                                vertCount += (short)_font.DrawLine(strikethroughStart < posx ? strikethroughStart : posx, -(line.y + line.baseline), lineWidth,

                                                    minFontSize, 1, vertList, uvList, uv2List, colList);

                                        }

                                        minFontSize = int.MaxValue;

                                    }

                                    else

                                        strikethroughStart = posx;

                                }

                                if (vertCount > 0 && _charPositions != null)

                                {

                                    CharPosition cp = _charPositions[_charPositions.Count - 1];

                                    cp.vertCount += vertCount;

                                    _charPositions[_charPositions.Count - 1] = cp;

                                }

                                format = element.format;

                                minFontSize = Math.Min(minFontSize, format.size);

                                maxFontSize = Math.Max(maxFontSize, format.size);

                                _font.SetFormat(format, _fontSizeScale);

                            }

                            else if (element.type == HtmlElementType.Link)

                            {

                                currentLink = (HtmlLink)element.htmlObject;

                                if (currentLink != null)

                                {

                                    element.position = Vector2.zero;

                                    currentLink.SetPosition(0, 0);

                                    linkStartX = posx;

                                    linkStartLine = i;

                                }

                            }

                            else if (element.type == HtmlElementType.LinkEnd)

                            {

                                if (currentLink != null)

                                {

                                    currentLink.SetArea(linkStartLine, linkStartX, i, posx);

                                    currentLink = null;

                                }

                            }

                            else

                            {

                                IHtmlObject htmlObj = element.htmlObject;

                                if (htmlObj != null)

                                {

                                    if (_textDirection == RTLSupport.DirectionType.RTL)

                                        posx -= htmlObj.width - 2;

                                    if (_charPositions != null)

                                    {

                                        CharPosition cp = new CharPosition();

                                        cp.lineIndex = (short)i;

                                        cp.charIndex = _charPositions.Count;

                                        cp.imgIndex = (short)(elementIndex + 1);

                                        cp.offsetX = posx;

                                        cp.width = (short)htmlObj.width;

                                        _charPositions.Add(cp);

                                    }

                                    if (lineClipped || clipping && (posx < GUTTER_X || posx > GUTTER_X && posx + htmlObj.width > _contentRect.width - GUTTER_X))

                                        element.status |= 1;

                                    else

                                        element.status &= 254;

                                    element.position = new Vector2(posx + 1, line.y + line.baseline - htmlObj.height * IMAGE_BASELINE);

                                    htmlObj.SetPosition(element.position.x, element.position.y);

                                    if (_textDirection == RTLSupport.DirectionType.RTL)

                                        posx -= letterSpacing;

                                    else

                                        posx += htmlObj.width + letterSpacing + 2;

                                }

                            }

                            if (element.isEntity)

                                ch = '\0';

                            elementIndex++;

                            if (elementIndex < elementCount)

                                element = _elements[elementIndex];

                            else

                                element = null;

                        }

                        if (ch == '\0')

                            continue;

    #if FAIRYGUI_TMPRO

                        if(_font.GetType() == typeof(TMPFont))

                        {

                            if (_font.GetGlyphWithFallback(ch == '\t' ? ' ' : ch, out glyphWidth, out glyphHeight, out baseline,out isFallback))

                            {

                                if (ch == '\t')

                                    glyphWidth *= 4;

                                if (_textDirection == RTLSupport.DirectionType.RTL)

                                {

                                    if (lineClipped || clipping && (rectWidth < 7 || posx != (indent_x - GUTTER_X)) && posx < GUTTER_X - 0.5f) //超出区域,剪裁

                                    {

                                        posx -= (letterSpacing + glyphWidth);

                                        continue;

                                    }

                                    posx -= glyphWidth;

                                }

                                else

                                {

                                    if (lineClipped || clipping && (rectWidth < 7 || posx != (GUTTER_X + indent_x)) && posx + glyphWidth > _contentRect.width - GUTTER_X + 0.5f) //超出区域,剪裁

                                    {

                                        posx += letterSpacing + glyphWidth;

                                        continue;

                                    }

                                }

                                if (isFallback == false)

                                {

                                    vertCount = (short)_font.DrawGlyph(posx, -(line.y + line.baseline), vertList, uvList, uv2List, colList);

                                    if (_charPositions != null)

                                    {

                                        CharPosition cp = new CharPosition();

                                        cp.lineIndex = (short)i;

                                        cp.charIndex = _charPositions.Count;

                                        cp.vertCount = vertCount;

                                        cp.offsetX = posx;

                                        cp.width = (short)glyphWidth;

                                        _charPositions.Add(cp);

                                    }

                                }

                                if (_textDirection == RTLSupport.DirectionType.RTL)

                                    posx -= letterSpacing;

                                else

                                    posx += letterSpacing + glyphWidth;

                            }

                            else //if GetGlyph failed

                            {

                                if (_charPositions != null)

                                {

                                    CharPosition cp = new CharPosition();

                                    cp.lineIndex = (short)i;

                                    cp.charIndex = _charPositions.Count;

                                    cp.offsetX = posx;

                                    _charPositions.Add(cp);

                                }

                                if (_textDirection == RTLSupport.DirectionType.RTL)

                                    posx -= letterSpacing;

                                else

                                    posx += letterSpacing;

                            }

                        }

                        else

                        {

                            if (_font.GetGlyph(ch == '\t' ? ' ' : ch, out glyphWidth, out glyphHeight, out baseline))

                            {

                                if (ch == '\t')

                                    glyphWidth *= 4;

                                if (_textDirection == RTLSupport.DirectionType.RTL)

                                {

                                    if (lineClipped || clipping && (rectWidth < 7 || posx != (indent_x - GUTTER_X)) && posx < GUTTER_X - 0.5f) //超出区域,剪裁

                                    {

                                        posx -= (letterSpacing + glyphWidth);

                                        continue;

                                    }

                                    posx -= glyphWidth;

                                }

                                else

                                {

                                    if (lineClipped || clipping && (rectWidth < 7 || posx != (GUTTER_X + indent_x)) && posx + glyphWidth > _contentRect.width - GUTTER_X + 0.5f) //超出区域,剪裁

                                    {

                                        posx += letterSpacing + glyphWidth;

                                        continue;

                                    }

                                }

                                vertCount = (short)_font.DrawGlyph(posx, -(line.y + line.baseline), vertList, uvList, uv2List, colList);

                                if (_charPositions != null)

                                {

                                    CharPosition cp = new CharPosition();

                                    cp.lineIndex = (short)i;

                                    cp.charIndex = _charPositions.Count;

                                    cp.vertCount = vertCount;

                                    cp.offsetX = posx;

                                    cp.width = (short)glyphWidth;

                                    _charPositions.Add(cp);

                                }

                                if (_textDirection == RTLSupport.DirectionType.RTL)

                                    posx -= letterSpacing;

                                else

                                    posx += letterSpacing + glyphWidth;

                            }

                            else //if GetGlyph failed

                            {

                                if (_charPositions != null)

                                {

                                    CharPosition cp = new CharPosition();

                                    cp.lineIndex = (short)i;

                                    cp.charIndex = _charPositions.Count;

                                    cp.offsetX = posx;

                                    _charPositions.Add(cp);

                                }

                                if (_textDirection == RTLSupport.DirectionType.RTL)

                                    posx -= letterSpacing;

                                else

                                    posx += letterSpacing;

                            }

                        }

    #else

    if (_font.GetGlyph(ch == '\t' ? ' ' : ch, out glyphWidth, out glyphHeight, out baseline))

                            {

                                Debug.Log("OnPopulateMesh GetGlyph:" + ch);

                                if (ch == '\t')

                                    glyphWidth *= 4;

                                if (_textDirection == RTLSupport.DirectionType.RTL)

                                {

                                    if (lineClipped || clipping && (rectWidth < 7 || posx != (indent_x - GUTTER_X)) && posx < GUTTER_X - 0.5f) //超出区域,剪裁

                                    {

                                        posx -= (letterSpacing + glyphWidth);

                                        continue;

                                    }

                                    posx -= glyphWidth;

                                }

                                else

                                {

                                    if (lineClipped || clipping && (rectWidth < 7 || posx != (GUTTER_X + indent_x)) && posx + glyphWidth > _contentRect.width - GUTTER_X + 0.5f) //超出区域,剪裁

                                    {

                                        posx += letterSpacing + glyphWidth;

                                        continue;

                                    }

                                }

                                vertCount = (short)_font.DrawGlyph(posx, -(line.y + line.baseline), vertList, uvList, uv2List, colList);

                                if (_charPositions != null)

                                {

                                    CharPosition cp = new CharPosition();

                                    cp.lineIndex = (short)i;

                                    cp.charIndex = _charPositions.Count;

                                    cp.vertCount = vertCount;

                                    cp.offsetX = posx;

                                    cp.width = (short)glyphWidth;

                                    _charPositions.Add(cp);

                                }

                                if (_textDirection == RTLSupport.DirectionType.RTL)

                                    posx -= letterSpacing;

                                else

                                    posx += letterSpacing + glyphWidth;

                            }

                            else //if GetGlyph failed

                            {

                                if (_charPositions != null)

                                {

                                    CharPosition cp = new CharPosition();

                                    cp.lineIndex = (short)i;

                                    cp.charIndex = _charPositions.Count;

                                    cp.offsetX = posx;

                                    _charPositions.Add(cp);

                                }

                                if (_textDirection == RTLSupport.DirectionType.RTL)

                                    posx -= letterSpacing;

                                else

                                    posx += letterSpacing;

                            }

    #endif

                    }//text loop

                    if (!lineClipped)

                    {

                        vertCount = 0;

                        if (format.underline)

                        {

                            float lineWidth;

                            if (_textDirection == RTLSupport.DirectionType.UNKNOW)

                                lineWidth = (clipping ? Mathf.Clamp(posx, GUTTER_X, GUTTER_X + rectWidth) : posx) - underlineStart;

                            else

                                lineWidth = underlineStart - (clipping ? Mathf.Clamp(posx, GUTTER_X, GUTTER_X + rectWidth) : posx);

                            if (lineWidth > 0)

                                vertCount += (short)_font.DrawLine(underlineStart < posx ? underlineStart : posx, -(line.y + line.baseline), lineWidth,

                                    maxFontSize, 0, vertList, uvList, uv2List, colList);

                        }

                        if (format.strikethrough)

                        {

                            float lineWidth;

                            if (_textDirection == RTLSupport.DirectionType.UNKNOW)

                                lineWidth = (clipping ? Mathf.Clamp(posx, GUTTER_X, GUTTER_X + rectWidth) : posx) - strikethroughStart;

                            else

                                lineWidth = strikethroughStart - (clipping ? Mathf.Clamp(posx, GUTTER_X, GUTTER_X + rectWidth) : posx);

                            if (lineWidth > 0)

                                vertCount += (short)_font.DrawLine(strikethroughStart < posx ? strikethroughStart : posx, -(line.y + line.baseline), lineWidth,

                                    minFontSize, 1, vertList, uvList, uv2List, colList);

                        }

                        if (vertCount > 0 && _charPositions != null)

                        {

                            CharPosition cp = _charPositions[_charPositions.Count - 1];

                            cp.vertCount += vertCount;

                            _charPositions[_charPositions.Count - 1] = cp;

                        }

                    }

                }//line loop

                if (element != null && element.type == HtmlElementType.LinkEnd && currentLink != null)

                    currentLink.SetArea(linkStartLine, linkStartX, lineCount - 1, posx);

                if (_charPositions != null)

                {

                    CharPosition cp = new CharPosition();

                    cp.lineIndex = (short)(lineCount - 1);

                    cp.charIndex = _charPositions.Count;

                    cp.offsetX = posx;

                    _charPositions.Add(cp);

                }

                int count = vertList.Count;

                if (count > 65000)

                {

                    Debug.LogWarning("Text is too large. A mesh may not have more than 65000 vertices.");

                    vertList.RemoveRange(65000, count - 65000);

                    colList.RemoveRange(65000, count - 65000);

                    uvList.RemoveRange(65000, count - 65000);

                    if (uv2List.Count > 0)

                        uv2List.RemoveRange(65000, count - 65000);

                    count = 65000;

                }

                if (_font.customOutline)

                {

                    bool hasShadow = _textFormat.shadowOffset.x != 0 || _textFormat.shadowOffset.y != 0;

                    int allocCount = count;

                    int drawDirs = 0;

                    if (_textFormat.outline != 0)

                    {

                        drawDirs = UIConfig.enhancedTextOutlineEffect ? 8 : 4;

                        allocCount += count * drawDirs;

                    }

                    if (hasShadow)

                        allocCount += count;

                    if (allocCount > 65000)

                    {

                        Debug.LogWarning("Text is too large. Outline/shadow effect cannot be completed.");

                        allocCount = count;

                    }

                    if (allocCount != count)

                    {

                        VertexBuffer vb2 = VertexBuffer.Begin();

                        List<Vector3> vertList2 = vb2.vertices;

                        List<Color32> colList2 = vb2.colors;

                        Color32 col = _textFormat.outlineColor;

                        float outline = _textFormat.outline;

                        if (outline != 0)

                        {

                            for (int j = 0; j < drawDirs; j++)

                            {

                                for (int i = 0; i < count; i++)

                                {

                                    Vector3 vert = vertList[i];

                                    vertList2.Add(new Vector3(vert.x + STROKE_OFFSET[j * 2] * outline, vert.y + STROKE_OFFSET[j * 2 + 1] * outline, 0));

                                    colList2.Add(col);

                                }

                                vb2.uvs.AddRange(uvList);

                                if (uv2List.Count > 0)

                                    vb2.uvs2.AddRange(uv2List);

                            }

                        }

                        if (hasShadow)

                        {

                            col = _textFormat.shadowColor;

                            Vector2 offset = _textFormat.shadowOffset;

                            for (int i = 0; i < count; i++)

                            {

                                Vector3 vert = vertList[i];

                                vertList2.Add(new Vector3(vert.x + offset.x, vert.y - offset.y, 0));

                                colList2.Add(col);

                            }

                            vb2.uvs.AddRange(uvList);

                            if (uv2List.Count > 0)

                                vb2.uvs2.AddRange(uv2List);

                        }

                        vb.Insert(vb2);

                        vb2.End();

                    }

                }

                vb.AddTriangles();

                if (_richTextField != null)

                    _richTextField.RefreshObjects();

            }

    目前还有很多支持不完善的地方,如果运行中动态修改GTextField的属性,需要将对应属性的变动同步到GSubTextField中,目前看只能在GTextField每个属性设置的地方添加实现,没找到更容易扩展的方式。开始想把GSubTextField挂在GTextField下作为子节点,这样诸如位置、缩放等的动态改变就不用额外考虑了,但实现中发现GTextField本身不是GComponen组件,由于本身对FairyGUI源码不太熟,不知道如何挂载,只能放在GTextField的同级下。

    相关文章

      网友评论

          本文标题:FairyGUI对TextMeshPro的fallback fo

          本文链接:https://www.haomeiwen.com/subject/ofiprrtx.html