美文网首页
NGUI-UILabel源码解析

NGUI-UILabel源码解析

作者: 白桦叶 | 来源:发表于2019-11-03 17:39 被阅读0次
    1. UILabel
      1.1 概述
      UILabel是NGUI中用于文字显示的组件,支持图文显示,富文本等功能。阅读本文前请熟悉下NGUI的基本用法和基本属性。
      1.2 基本用法


      UILabel1.png
    UILabel2.png

    1.3 基础属性
    溢出类型
    效果类型
    字体类型
    对齐方式
    图文样式
    渐变
    边距
    支持富文本
    多行和最高行数

    1.4 基本原理

    • 字体方案有两种:Unity的动态字体(trueTypeFont,TTF)和NGUI的BitmapFont(BMFont
    • UILabel维护mShouldBeProcessed的bool变量,在设置基本属性的时候都会将mShouldBeProcessed设置为true,并重写父类UIWidget的属性drawingDimensions、localCorners、worldCorners、localSize和方法GetSides中判断shouldBeProcessed是否为true,为true则调用UILabel的ProcessText重新计算信息并重新绘制。
    • NGUIText作为辅助类,是一个静态类,由于绘制文字的参数很多,由其参数缓存和相应的计算方法,减少相应的内存占用。
    1. UILabel核心方法
      2.1 ProcessText
      2.1.1 流程
    • 计算UILabel设定的矩形大小和真正显示的矩形大小,其设定矩形大小还受OverFlow类型的影响,如类型为Overflow.ResizeFreely或者Overflow.ResizeHeight相应的设定大小不受当前width height的限制。
    • 调用NGUIText.Update(false):更新最终字形的大小、字符间隔finalSpacingX、 一行高度finalLineHeight和是否用符文等信息。
    • 启用for循环不断递减字体大小
      • 调用NGUIText.WrapText(mText, out mProcessedText, true);
        • 根据regionHeight、finalLineHeight和maxLines计算出Label最多显示的行数;不断遍历字符,解析BBCode跳过用于富文本设置的字符,区分普通字符和图文字符分别计算其字形大小glyphWidth,维护每一行剩余的宽度remainingWidth,当宽度不足的时候就换行,最后返回Label是否容纳全部文本,并得到最终显示的文本finalText。
    • 调用NGUIText.CalculatePrintedSize(mProcessedText):
      • 根据显示的文本mProcessedText和字符间隔finalSpacingX、 一行高度finalLineHeight得到显示rect大小
    • 根据不同OverFlow类型计算Label的宽度和高度。
      2.1.2 OverFlow的处理方式
    • ShrinkContent:缩放内容;不断递减mPrintedSize调用NGUIText.WrapText(mText, out mProcessedText, true);判断目前字体大小是否能显示全部文字,直至满足条件或者字体大小不能再减小。
    • ClampContent:裁切内容;调用调用NGUIText.WrapText(mText, out mProcessedText, true);得到最终显示的文字。
    • ResizeFreely:自适应宽高;调用调用NGUIText.WrapText(mText, out mProcessedText, true);得到最终显示的文字。并调用NGUIText.CalculatePrintedSize(mProcessedText);得到显示的大小,重新计算widget的宽高
    • ResizeHeight:自适应高度;类似ResizeFreely,只是重新计算widget的高度。

    2.1.3 代码

        void ProcessText (bool legacyMode, bool full)
        {
            if (!isValid) return;
    
            mChanged = true;
            shouldBeProcessed = false;
    
            float regionX = mDrawRegion.z - mDrawRegion.x;
            float regionY = mDrawRegion.w - mDrawRegion.y;
    
            NGUIText.rectWidth    = legacyMode ? (mMaxLineWidth  != 0 ? mMaxLineWidth  : 1000000) : width;
            NGUIText.rectHeight   = legacyMode ? (mMaxLineHeight != 0 ? mMaxLineHeight : 1000000) : height;
            NGUIText.regionWidth  = (regionX != 1f) ? Mathf.RoundToInt(NGUIText.rectWidth  * regionX) : NGUIText.rectWidth;
            NGUIText.regionHeight = (regionY != 1f) ? Mathf.RoundToInt(NGUIText.rectHeight * regionY) : NGUIText.rectHeight;
    
            mPrintedSize = Mathf.Abs(legacyMode ? Mathf.RoundToInt(cachedTransform.localScale.x) : defaultFontSize);
            mScale = 1f;
    
            if (NGUIText.regionWidth < 1 || NGUIText.regionHeight < 0)
            {
                mProcessedText = "";
                return;
            }
    
    #if DYNAMIC_FONT
            bool isDynamic = (trueTypeFont != null);
    
            if (isDynamic && keepCrisp)
            {
                UIRoot rt = root;
                if (rt != null) mDensity = (rt != null) ? rt.pixelSizeAdjustment : 1f;
            }
            else mDensity = 1f;
    #endif
            if (full) UpdateNGUIText();
    
            if (mOverflow == Overflow.ResizeFreely)
            {
                NGUIText.rectWidth = 1000000;
                NGUIText.regionWidth = 1000000;
            }
    
            if (mOverflow == Overflow.ResizeFreely || mOverflow == Overflow.ResizeHeight)
            {
                NGUIText.rectHeight = 1000000;
                NGUIText.regionHeight = 1000000;
            }
    
            if (mPrintedSize > 0)
            {
    #if DYNAMIC_FONT
                bool adjustSize = keepCrisp;
    #endif
                for (int ps = mPrintedSize; ps > 0; --ps)
                {
    #if DYNAMIC_FONT
                    // Adjust either the size, or the scale
                    if (adjustSize)
                    {
                        mPrintedSize = ps;
                        NGUIText.fontSize = mPrintedSize;
                    }
                    else
    #endif
                    {
                        mScale = (float)ps / mPrintedSize;
    #if DYNAMIC_FONT
                        NGUIText.fontScale = isDynamic ? mScale : ((float)mFontSize / mFont.defaultSize) * mScale;
    #else
                        NGUIText.fontScale = ((float)mFontSize / mFont.defaultSize) * mScale;
    #endif
                    }
    
                    NGUIText.Update(false);
    
                    // Wrap the text
                    bool fits = NGUIText.WrapText(mText, out mProcessedText, true);
    
                    if (mOverflow == Overflow.ShrinkContent && !fits)
                    {
                        if (--ps > 1) continue;
                        else break;
                    }
                    else if (mOverflow == Overflow.ResizeFreely)
                    {
                        mCalculatedSize = NGUIText.CalculatePrintedSize(mProcessedText);
    
                        mWidth = Mathf.Max(minWidth, Mathf.RoundToInt(mCalculatedSize.x));
                        if (regionX != 1f) mWidth = Mathf.RoundToInt(mWidth / regionX);
                        mHeight = Mathf.Max(minHeight, Mathf.RoundToInt(mCalculatedSize.y));
                        if (regionY != 1f) mHeight = Mathf.RoundToInt(mHeight / regionY);
    
                        if ((mWidth & 1) == 1) ++mWidth;
                        if ((mHeight & 1) == 1) ++mHeight;
                    }
                    else if (mOverflow == Overflow.ResizeHeight)
                    {
                        mCalculatedSize = NGUIText.CalculatePrintedSize(mProcessedText);
                        mHeight = Mathf.Max(minHeight, Mathf.RoundToInt(mCalculatedSize.y));
                        if (regionY != 1f) mHeight = Mathf.RoundToInt(mHeight / regionY);
                        if ((mHeight & 1) == 1) ++mHeight;
                    }
                    else
                    {
                        mCalculatedSize = NGUIText.CalculatePrintedSize(mProcessedText);
                    }
    
                    // Upgrade to the new system
                    if (legacyMode)
                    {
                        width = Mathf.RoundToInt(mCalculatedSize.x);
                        height = Mathf.RoundToInt(mCalculatedSize.y);
                        cachedTransform.localScale = Vector3.one;
                    }
                    break;
                }
            }
            else
            {
                cachedTransform.localScale = Vector3.one;
                mProcessedText = "";
                mScale = 1f;
            }
            
            if (full)
            {
                NGUIText.bitmapFont = null;
    #if DYNAMIC_FONT
                NGUIText.dynamicFont = null;
    #endif
            }
        }
    

    2.2 OnFill
    2.2.1 流程

    • UpdateNGUIText:更新设置当前UILabel的属性给NGUIText
    • NGUIText.Print(text, verts, uvs, cols):根据显示的文本填入几何数据到缓存中
    • ApplyOffset:根据Pivot类型调整顶点位置
    • 对于Effect非None情形,以下是3个类型的原理
      • Effect.Shadow:阴影;调用ApplyShadow增加阴影处理,ApplyShadow的作用是将之前填入的当前UILabel最终显示的文本顶点、UV、Color数据重新填入一次,其中顶点做根据UILabel的mEffectDistance的属性做相应的偏差处理,Effect.Shadow是偏右下,因此呈现出阴影效果。
      • Effect.Outline:描边;调用ApplyShadow增加4个方向的阴影处理,分别是右下,左上,右上,左下,则相当于描边作用
      • Effect.Outline8:8个方向的描边,类似于Effect.Outline,方向相对于前置增加了正右,正上,正左,正下。

    2.2.2 代码

    public override void OnFill (BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols)
        {
            if (!isValid) return;
    
            int offset = verts.size;
            Color col = color;
            col.a = finalAlpha;
            
            if (mFont != null && mFont.premultipliedAlphaShader) col = NGUITools.ApplyPMA(col);
    
            if (QualitySettings.activeColorSpace == ColorSpace.Linear)
            {
                col.r = Mathf.GammaToLinearSpace(col.r);
                col.g = Mathf.GammaToLinearSpace(col.g);
                col.b = Mathf.GammaToLinearSpace(col.b);
            }
    
            string text = processedText;
            int start = verts.size;
    
            UpdateNGUIText();
    
            NGUIText.tint = col;
            NGUIText.Print(text, verts, uvs, cols);
            NGUIText.bitmapFont = null;
    #if DYNAMIC_FONT
            NGUIText.dynamicFont = null;
    #endif
            // Center the content within the label vertically
            Vector2 pos = ApplyOffset(verts, start);
    
            // Effects don't work with packed fonts
            if (mFont != null && mFont.packedFontShader) return;
    
            // Apply an effect if one was requested
            if (effectStyle != Effect.None)
            {
                int end = verts.size;
                pos.x = mEffectDistance.x;
                pos.y = mEffectDistance.y;
    
                ApplyShadow(verts, uvs, cols, offset, end, pos.x, -pos.y);
    
                if ((effectStyle == Effect.Outline) || (effectStyle == Effect.Outline8))
                {
                    offset = end;
                    end = verts.size;
    
                    ApplyShadow(verts, uvs, cols, offset, end, -pos.x, pos.y);
    
                    offset = end;
                    end = verts.size;
    
                    ApplyShadow(verts, uvs, cols, offset, end, pos.x, pos.y);
    
                    offset = end;
                    end = verts.size;
    
                    ApplyShadow(verts, uvs, cols, offset, end, -pos.x, -pos.y);
    
                    if (effectStyle == Effect.Outline8)
                    {
                        offset = end;
                        end = verts.size;
    
                        ApplyShadow(verts, uvs, cols, offset, end, -pos.x, 0);
    
                        offset = end;
                        end = verts.size;
    
                        ApplyShadow(verts, uvs, cols, offset, end, pos.x, 0);
    
                        offset = end;
                        end = verts.size;
    
                        ApplyShadow(verts, uvs, cols, offset, end, 0, pos.y);
    
                        offset = end;
                        end = verts.size;
    
                        ApplyShadow(verts, uvs, cols, offset, end, 0, -pos.y);
                    }
                }
            }
    
            if (onPostFill != null)
                onPostFill(this, offset, verts, uvs, cols);
        }
    
    1. NGUIText
      3.1 NGUIText核心方法
      NGUIText.Print(text, verts, uvs, cols):(普通字符的处理、图文字符的处理),顶点、UV和Color数据分别按照左下、左上、右上、右下顺序填入缓存中。
      3.1.1 流程
    • Prepare:当使用动态字体时,调用Font.RequestCharactersInTexture刷新所需字符的纹理
    • 遍历text的每个字符
    • 处理换行符 不处理非法字符
    • ParseSymbol 解析BBCode:该函数带有多个ref值,分别为subscriptMode上下标,bold加粗,italic斜体, underline下划线, strikethrough中划线, ignoreColor忽略widget的颜色,即使用富文本的颜色。
    • GetSymbol:获取对应的图文字符信息,没有匹配则返回null
      • 处理图文字符

        • 计算符号图文的显示范围
        • 如果宽度容纳不下 换行
        • 添加顶点、UV、Color信息到缓存
        • 其中SymbolStyle等于Colored的时候,图案的颜色使用当前字体颜色,其中情况下只使用当前的alpha值,rgb通道均为255。
      • 处理普通字符

        • GetGlyph(ch, prev);获取字形信息,根据使用的是bitmapFont还是dynamicFont计算得到字形数据GlyphInfo,里面包含字形的顶点坐标,uv坐标和颜色channel通道设置。

          • GlyphInfo数据结构
          public class GlyphInfo
            {
                public Vector2 v0;
                public Vector2 v1;
                public Vector2 u0;
                public Vector2 u1;
                public Vector2 u2;
                public Vector2 u3;
                public float advance = 0f;
                public int channel = 0;
          }       
          
      • 有上下标

        • glyph的两个顶点glyph.v0和glyph.v1乘以一个比例值sizeShrinkage都缩小,缩小顶点范围
        • 根据上标还是下标对顶点进行上下偏移Y坐标
      • 如果宽度不够 换行处理

      • 若字符为空格:若BBCode对应是下划线,则替换为“下划线”;若对应中划线,都不对应,则continue

      • 处理纹理坐标:添加纹理坐标到缓存中

      • 根据GlyphInfo的channel值-》处理顶点颜色,填入Color信息

        • 当前channel为0或者为15的时候,对于渐变情况做下处理,算法是:计算出字体顶点y轴最高点和最低点的在整体字体显示的比例,通过渐变底部和顶部的颜色插值得到对应顶部和底部两个颜色值。
      • 根据粗体斜体处理顶点坐标

        • 粗体 相当于每个字符渲染4次,对顶点坐标进行一定的偏移
        • 斜体 相当于每个字符顶点有一定偏移
      • 处理下划线或中划线

        • 获取对应GlyphInfo信息
        • 类似上述进行处理
    • 处理alignment为居中或右侧的情况:默认按照从左往右,即Alignment.Left方式处理
      • Alignment.Right:计算显示宽度与文本宽度的差值,如果差值padding大于0,将顶点坐标的x坐标向右偏移padding
      • Alignment.Center:计算显示宽度与文本宽度的差值的一半padding,如果差值padding大于0,将顶点坐标的x坐标向右偏移padding
      • Alignment.Justified:
        • 文本宽度需要大于显示宽度的65%;
        • 计算显示宽度与文本宽度的差值的一半padding
        • 将字符平均显示在显示区域上

    3.1.2 代码

    static public void Print (string text, BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols)
        {
            if (string.IsNullOrEmpty(text)) return;
    
            int indexOffset = verts.size;
            Prepare(text);
    
            // Start with the white tint
            mColors.Add(Color.white);
            mAlpha = 1f;
    
            int ch = 0, prev = 0;
            float x = 0f, y = 0f, maxX = 0f;
            float sizeF = finalSize;
    
            Color gb = tint * gradientBottom;
            Color gt = tint * gradientTop;
            Color32 uc = tint;
            int textLength = text.Length;
    
            Rect uvRect = new Rect();
            float invX = 0f, invY = 0f;
            float sizePD = sizeF * pixelDensity;
    
            // Advanced symbol support contributed by Rudy Pangestu.
            bool subscript = false;
            int subscriptMode = 0;  // 0 = normal, 1 = subscript, 2 = superscript
            bool bold = false;
            bool italic = false;
            bool underline = false;
            bool strikethrough = false;
            bool ignoreColor = false;
            const float sizeShrinkage = 0.75f;
    
            float v0x;
            float v1x;
            float v1y;
            float v0y;
            float prevX = 0;
    
            if (bitmapFont != null)
            {
                uvRect = bitmapFont.uvRect;
                invX = uvRect.width / bitmapFont.texWidth;
                invY = uvRect.height / bitmapFont.texHeight;
            }
    
            for (int i = 0; i < textLength; ++i)
            {
                ch = text[i];
    
                prevX = x;
    
                // New line character -- skip to the next line
                if (ch == '\n')
                {
                    if (x > maxX) maxX = x;
    
                    if (alignment != Alignment.Left)
                    {
                        Align(verts, indexOffset, x - finalSpacingX);
                        indexOffset = verts.size;
                    }
    
                    x = 0;
                    y += finalLineHeight;
                    prev = 0;
                    continue;
                }
    
                // Invalid character -- skip it
                if (ch < ' ')
                {
                    prev = ch;
                    continue;
                }
    
                // Color changing symbol
                if (encoding && ParseSymbol(text, ref i, mColors, premultiply, ref subscriptMode, ref bold,
                    ref italic, ref underline, ref strikethrough, ref ignoreColor))
                {
                    Color fc;
    
                    if (ignoreColor)
                    {
                        fc = mColors[mColors.size - 1];
                        fc.a *= mAlpha * tint.a;
                    }
                    else
                    {
                        fc = tint * mColors[mColors.size - 1];
                        fc.a *= mAlpha;
                    }
                    uc = fc;
    
                    for (int b = 0, bmax = mColors.size - 2; b < bmax; ++b)
                        fc.a *= mColors[b].a;
    
                    if (gradient)
                    {
                        gb = gradientBottom * fc;
                        gt = gradientTop * fc;
                    }
                    --i;
                    continue;
                }
    
                // See if there is a symbol matching this text
                BMSymbol symbol = useSymbols ? GetSymbol(text, i, textLength) : null;
    
                if (symbol != null)
                {
                    v0x = x + symbol.offsetX * fontScale;
                    v1x = v0x + symbol.width * fontScale;
                    v1y = -(y + symbol.offsetY * fontScale);
                    v0y = v1y - symbol.height * fontScale;
    
                    // Doesn't fit? Move down to the next line
                    if (Mathf.RoundToInt(x + symbol.advance * fontScale) > regionWidth)
                    {
                        if (x == 0f) return;
    
                        if (alignment != Alignment.Left && indexOffset < verts.size)
                        {
                            Align(verts, indexOffset, x - finalSpacingX);
                            indexOffset = verts.size;
                        }
    
                        v0x -= x;
                        v1x -= x;
                        v0y -= finalLineHeight;
                        v1y -= finalLineHeight;
    
                        x = 0;
                        y += finalLineHeight;
                        prevX = 0;
                    }
    
                    verts.Add(new Vector3(v0x, v0y));
                    verts.Add(new Vector3(v0x, v1y));
                    verts.Add(new Vector3(v1x, v1y));
                    verts.Add(new Vector3(v1x, v0y));
    
                    x += finalSpacingX + symbol.advance * fontScale;
                    i += symbol.length - 1;
                    prev = 0;
    
                    if (uvs != null)
                    {
                        Rect uv = symbol.uvRect;
    
                        float u0x = uv.xMin;
                        float u0y = uv.yMin;
                        float u1x = uv.xMax;
                        float u1y = uv.yMax;
    
                        uvs.Add(new Vector2(u0x, u0y));
                        uvs.Add(new Vector2(u0x, u1y));
                        uvs.Add(new Vector2(u1x, u1y));
                        uvs.Add(new Vector2(u1x, u0y));
                    }
    
                    if (cols != null)
                    {
                        if (symbolStyle == SymbolStyle.Colored)
                        {
                            for (int b = 0; b < 4; ++b) cols.Add(uc);
                        }
                        else
                        {
                            Color32 col = Color.white;
                            col.a = uc.a;
                            for (int b = 0; b < 4; ++b) cols.Add(col);
                        }
                    }
                }
                else // No symbol present
                {
                    GlyphInfo glyph = GetGlyph(ch, prev);
                    if (glyph == null) continue;
                    prev = ch;
    
                    if (subscriptMode != 0)
                    {
                        glyph.v0.x *= sizeShrinkage;
                        glyph.v0.y *= sizeShrinkage;
                        glyph.v1.x *= sizeShrinkage;
                        glyph.v1.y *= sizeShrinkage;
    
                        if (subscriptMode == 1)
                        {
                            glyph.v0.y -= fontScale * fontSize * 0.4f;
                            glyph.v1.y -= fontScale * fontSize * 0.4f;
                        }
                        else
                        {
                            glyph.v0.y += fontScale * fontSize * 0.05f;
                            glyph.v1.y += fontScale * fontSize * 0.05f;
                        }
                    }
    
                    v0x = glyph.v0.x + x;
                    v0y = glyph.v0.y - y;
                    v1x = glyph.v1.x + x;
                    v1y = glyph.v1.y - y;
    
                    float w = glyph.advance;
                    if (finalSpacingX < 0f) w += finalSpacingX;
    
                    // Doesn't fit? Move down to the next line
                    if (Mathf.RoundToInt(x + w) > regionWidth)
                    {
                        if (x == 0f) return;
    
                        if (alignment != Alignment.Left && indexOffset < verts.size)
                        {
                            Align(verts, indexOffset, x - finalSpacingX);
                            indexOffset = verts.size;
                        }
    
                        v0x -= x;
                        v1x -= x;
                        v0y -= finalLineHeight;
                        v1y -= finalLineHeight;
    
                        x = 0;
                        y += finalLineHeight;
                        prevX = 0;
                    }
    
                    if (IsSpace(ch))
                    {
                        if (underline)
                        {
                            ch = '_';
                        }
                        else if (strikethrough)
                        {
                            ch = '-';
                        }
                    }
    
                    // Advance the position
                    x += (subscriptMode == 0) ? finalSpacingX + glyph.advance :
                        (finalSpacingX + glyph.advance) * sizeShrinkage;
    
                    // No need to continue if this is a space character
                    if (IsSpace(ch)) continue;
    
                    // Texture coordinates
                    if (uvs != null)
                    {
                        if (bitmapFont != null)
                        {
                            glyph.u0.x = uvRect.xMin + invX * glyph.u0.x;
                            glyph.u2.x = uvRect.xMin + invX * glyph.u2.x;
                            glyph.u0.y = uvRect.yMax - invY * glyph.u0.y;
                            glyph.u2.y = uvRect.yMax - invY * glyph.u2.y;
    
                            glyph.u1.x = glyph.u0.x;
                            glyph.u1.y = glyph.u2.y;
    
                            glyph.u3.x = glyph.u2.x;
                            glyph.u3.y = glyph.u0.y;
                        }
    
                        for (int j = 0, jmax = (bold ? 4 : 1); j < jmax; ++j)
                        {
                            uvs.Add(glyph.u0);
                            uvs.Add(glyph.u1);
                            uvs.Add(glyph.u2);
                            uvs.Add(glyph.u3);
                        }
                    }
    
                    // Vertex colors
                    if (cols != null)
                    {
                        if (glyph.channel == 0 || glyph.channel == 15)
                        {
                            if (gradient)
                            {
                                float min = sizePD + glyph.v0.y / fontScale;
                                float max = sizePD + glyph.v1.y / fontScale;
    
                                min /= sizePD;
                                max /= sizePD;
    
                                s_c0 = Color.Lerp(gb, gt, min);
                                s_c1 = Color.Lerp(gb, gt, max);
    
                                for (int j = 0, jmax = (bold ? 4 : 1); j < jmax; ++j)
                                {
                                    cols.Add(s_c0);
                                    cols.Add(s_c1);
                                    cols.Add(s_c1);
                                    cols.Add(s_c0);
                                }
                            }
                            else
                            {
                                for (int j = 0, jmax = (bold ? 16 : 4); j < jmax; ++j)
                                    cols.Add(uc);
                            }
                        }
                        else
                        {
                            // Packed fonts come as alpha masks in each of the RGBA channels.
                            // In order to use it we need to use a special shader.
                            //
                            // Limitations:
                            // - Effects (drop shadow, outline) will not work.
                            // - Should not be a part of the atlas (eastern fonts rarely are anyway).
                            // - Lower color precision
    
                            Color col = uc;
    
                            col *= 0.49f;
    
                            switch (glyph.channel)
                            {
                                case 1: col.b += 0.51f; break;
                                case 2: col.g += 0.51f; break;
                                case 4: col.r += 0.51f; break;
                                case 8: col.a += 0.51f; break;
                            }
    
                            Color32 c = col;
                            for (int j = 0, jmax = (bold ? 16 : 4); j < jmax; ++j)
                                cols.Add(c);
                        }
                    }
    
                    // Bold and italic contributed by Rudy Pangestu.
                    if (!bold)
                    {
                        if (!italic)
                        {
                            verts.Add(new Vector3(v0x, v0y));
                            verts.Add(new Vector3(v0x, v1y));
                            verts.Add(new Vector3(v1x, v1y));
                            verts.Add(new Vector3(v1x, v0y));
                        }
                        else // Italic
                        {
                            float slant = fontSize * 0.1f * ((v1y - v0y) / fontSize);
                            verts.Add(new Vector3(v0x - slant, v0y));
                            verts.Add(new Vector3(v0x + slant, v1y));
                            verts.Add(new Vector3(v1x + slant, v1y));
                            verts.Add(new Vector3(v1x - slant, v0y));
                        }
                    }
                    else // Bold
                    {
                        for (int j = 0; j < 4; ++j)
                        {
                            float a = mBoldOffset[j * 2];
                            float b = mBoldOffset[j * 2 + 1];
    
                            float slant = (italic ? fontSize * 0.1f * ((v1y - v0y) / fontSize) : 0f);
                            verts.Add(new Vector3(v0x + a - slant, v0y + b));
                            verts.Add(new Vector3(v0x + a + slant, v1y + b));
                            verts.Add(new Vector3(v1x + a + slant, v1y + b));
                            verts.Add(new Vector3(v1x + a - slant, v0y + b));
                        }
                    }
    
                    // Underline and strike-through contributed by Rudy Pangestu.
                    if (underline || strikethrough)
                    {
                        GlyphInfo dash = GetGlyph(strikethrough ? '-' : '_', prev);
                        if (dash == null) continue;
    
                        if (uvs != null)
                        {
                            if (bitmapFont != null)
                            {
                                dash.u0.x = uvRect.xMin + invX * dash.u0.x;
                                dash.u2.x = uvRect.xMin + invX * dash.u2.x;
                                dash.u0.y = uvRect.yMax - invY * dash.u0.y;
                                dash.u2.y = uvRect.yMax - invY * dash.u2.y;
                            }
    
                            float cx = (dash.u0.x + dash.u2.x) * 0.5f;
    
                            for (int j = 0, jmax = (bold ? 4 : 1); j < jmax; ++j)
                            {
                                uvs.Add(new Vector2(cx, dash.u0.y));
                                uvs.Add(new Vector2(cx, dash.u2.y));
                                uvs.Add(new Vector2(cx, dash.u2.y));
                                uvs.Add(new Vector2(cx, dash.u0.y));
                            }
                        }
    
                        if (subscript && strikethrough)
                        {
                            v0y = (-y + dash.v0.y) * sizeShrinkage;
                            v1y = (-y + dash.v1.y) * sizeShrinkage;
                        }
                        else
                        {
                            v0y = (-y + dash.v0.y);
                            v1y = (-y + dash.v1.y);
                        }
    
                        if (bold)
                        {
                            for (int j = 0; j < 4; ++j)
                            {
                                float a = mBoldOffset[j * 2];
                                float b = mBoldOffset[j * 2 + 1];
    
                                verts.Add(new Vector3(prevX + a, v0y + b));
                                verts.Add(new Vector3(prevX + a, v1y + b));
                                verts.Add(new Vector3(x + a, v1y + b));
                                verts.Add(new Vector3(x + a, v0y + b));
                            }
                        }
                        else
                        {
                            verts.Add(new Vector3(prevX, v0y));
                            verts.Add(new Vector3(prevX, v1y));
                            verts.Add(new Vector3(x, v1y));
                            verts.Add(new Vector3(x, v0y));
                        }
    
                        if (gradient)
                        {
                            float min = sizePD + dash.v0.y / fontScale;
                            float max = sizePD + dash.v1.y / fontScale;
    
                            min /= sizePD;
                            max /= sizePD;
    
                            s_c0 = Color.Lerp(gb, gt, min);
                            s_c1 = Color.Lerp(gb, gt, max);
    
                            for (int j = 0, jmax = (bold ? 4 : 1); j < jmax; ++j)
                            {
                                cols.Add(s_c0);
                                cols.Add(s_c1);
                                cols.Add(s_c1);
                                cols.Add(s_c0);
                            }
                        }
                        else
                        {
                            for (int j = 0, jmax = (bold ? 16 : 4); j < jmax; ++j)
                                cols.Add(uc);
                        }
                    }
                }
            }
    
            if (alignment != Alignment.Left && indexOffset < verts.size)
            {
                Align(verts, indexOffset, x - finalSpacingX);
                indexOffset = verts.size;
            }
            mColors.Clear();
        }
    

    相关文章

      网友评论

          本文标题:NGUI-UILabel源码解析

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