zoukankan      html  css  js  c++  java
  • NGUI中动态字体图文混排

    用到的场景:聊天系统。

    NGUI版本:3.5.6。


    已支持的功能,静态(位图)字体的图文混排。


    需要实现的:动态字体的图文混排。


    实现思路:用两个Label,一个只负责渲染文字,一个负责渲染图片。用isSymbol区分是渲染图片还是渲染文字。渲染文字的跳过符号的顶点和uv的添加,渲染图片的跳过正常字符的顶点和uv添加。


    修改NGUIText.cs的代码如下:

    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);
    
    		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;
    		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;
            }
            else
            {
                if (symbolFont != null && useWgSymbol)
                {
                    uvRect = symbolFont.uvRect;
                    invX = uvRect.width / symbolFont.texWidth;
                    invY = uvRect.height / symbolFont.texHeight;
                }
            }
    
    
    
    		for (int i = 0; i < textLength; ++i)
    		{
    			ch = text[i];
    
    			prevX = x;
    
    			// New line character -- skip to the next line
    			if (ch == '
    ')
    			{
    				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))
    			{
    				Color fc = tint * mColors[mColors.size - 1];
    				uc = fc;
    
    				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) > rectWidth)
    				{
    					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 (isSymbol || !useWgSymbol)
                    {
                        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;
                        if (isSymbol || !useWgSymbol)
                        {
                            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)
                        {
                            if (isSymbol || !useWgSymbol)
                            {
                                for (int b = 0; b < 4; ++b) cols.Add(uc);
                            }
    					}
    					else
    					{
    						Color32 col = Color.white;
                            col.a = uc.a;
                            if (isSymbol || !useWgSymbol)
                            {
                                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;
    					}
    				}
    
    				float y0 = glyph.v0.y;
    				float y1 = glyph.v1.y;
    
    				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) > rectWidth)
    				{
    					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 (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 (ch == ' ') continue;
    
    				// Texture coordinates
    				if (uvs != null)
    				{
    					if (bitmapFont != null)
    					{
    						glyph.u0.x = uvRect.xMin + invX * glyph.u0.x;
    						glyph.u1.x = uvRect.xMin + invX * glyph.u1.x;
    						glyph.u0.y = uvRect.yMax - invY * glyph.u0.y;
    						glyph.u1.y = uvRect.yMax - invY * glyph.u1.y;
    					}
    
                        if (!isSymbol || !useWgSymbol)
                        {
                            for (int j = 0, jmax = (bold ? 4 : 1); j < jmax; ++j)
                            {
                                if (glyph.rotatedUVs)
                                {
                                    uvs.Add(glyph.u0);
                                    uvs.Add(new Vector2(glyph.u1.x, glyph.u0.y));
                                    uvs.Add(glyph.u1);
                                    uvs.Add(new Vector2(glyph.u0.x, glyph.u1.y));
                                }
                                else
                                {
                                    uvs.Add(glyph.u0);
                                    uvs.Add(new Vector2(glyph.u0.x, glyph.u1.y));
                                    uvs.Add(glyph.u1);
                                    uvs.Add(new Vector2(glyph.u1.x, glyph.u0.y));
                                }
                            }
                        }
    				}
    
    				// Vertex colors
    				if (cols != null)
    				{
    					if (glyph.channel == 0 || glyph.channel == 15)
    					{
    						if (gradient)
    						{
    							float min = sizePD + y0 / fontScale;
    							float max = sizePD + y1 / fontScale;
    
    							min /= sizePD;
    							max /= sizePD;
    
    							s_c0 = Color.Lerp(gb, gt, min);
    							s_c1 = Color.Lerp(gb, gt, max);
                                if (!isSymbol || !useWgSymbol)
                                {
                                    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
                            {
                                if (!isSymbol || !useWgSymbol)
                                {
                                    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;
    						}
                            if (!isSymbol || !useWgSymbol)
                            {
                                Color32 c = col;
                                for (int j = 0, jmax = (bold ? 16 : 4); j < jmax; ++j)
                                    cols.Add(c);
                            }
    					}
    				}
                    if (!isSymbol || !useWgSymbol)
                    {
                        // 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 = a + (italic ? fontSize * 0.1f * ((v1y - v0y) / fontSize) : 0f);
                                verts.Add(new Vector3(v0x - slant, v0y + b));
                                verts.Add(new Vector3(v0x + slant, v1y + b));
                                verts.Add(new Vector3(v1x + slant, v1y + b));
                                verts.Add(new Vector3(v1x - slant, v0y + b));
                            }
                        }
                    }
    
    				// Underline and strike-through contributed by Rudy Pangestu.
    				if (underline || strikethrough)
    				{
    					GlyphInfo dash = GetGlyph(strikethrough ? '-' : '_', prev);
    					if (dash == null) continue;
                        if (!isSymbol || !useWgSymbol)
                        {
                            if (uvs != null)
                            {
                                if (bitmapFont != null)
                                {
                                    dash.u0.x = uvRect.xMin + invX * dash.u0.x;
                                    dash.u1.x = uvRect.xMin + invX * dash.u1.x;
                                    dash.u0.y = uvRect.yMax - invY * dash.u0.y;
                                    dash.u1.y = uvRect.yMax - invY * dash.u1.y;
                                }
    
                                float cx = (dash.u0.x + dash.u1.x) * 0.5f;
                                float cy = (dash.u0.y + dash.u1.y) * 0.5f;
    
                                uvs.Add(new Vector2(cx, cy));
                                uvs.Add(new Vector2(cx, cy));
                                uvs.Add(new Vector2(cx, cy));
                                uvs.Add(new Vector2(cx, cy));
                            }
                        }
    
    					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 (!isSymbol || !useWgSymbol)
                        {
                            verts.Add(new Vector3(prevX, v0y));
                            verts.Add(new Vector3(prevX, v1y));
                            verts.Add(new Vector3(x, v1y));
                            verts.Add(new Vector3(x, v0y));
                        }
    
    					Color tint2 = uc;
    
    					if (strikethrough)
    					{
    						tint2.r *= 0.5f;
    						tint2.g *= 0.5f;
    						tint2.b *= 0.5f;
    					}
    					tint2.a *= 0.75f;
    					Color32 uc2 = tint2;
                        if (!isSymbol || !useWgSymbol)
                        {
                            cols.Add(uc2);
                            cols.Add(uc);
                            cols.Add(uc);
                            cols.Add(uc2);
                        }
    				}
    			}
    		}
    
    		if (alignment != Alignment.Left && indexOffset < verts.size)
    		{
    			Align(verts, indexOffset, x - finalSpacingX);
    			indexOffset = verts.size;
    		}
    		mColors.Clear();
    	}


  • 相关阅读:
    js手写弹框和按钮显示
    Java类加载机制、双亲委派、Java类加载过程
    Java集合:HashMap必知必会
    查看oracle是否锁表
    消息队列Rabbit MQ 学习第一篇
    数据库blob图片文件,多图片打包下载
    HttpDebug下载
    将博客搬至CSDN
    android事件拦截处理机制详解
    回调函数
  • 原文地址:https://www.cnblogs.com/wugang/p/14232324.html
Copyright © 2011-2022 走看看