public SimpleUIPointSpriteStringElement(IUILayoutParam param, string content, vec3 position, GLColor color = null, int fontSize = 32, int maxRowWidth = 256, FontResource fontResource = null) { IUILayout layout = this; layout.Param = param; this.element = new PointSpriteStringElement(content, position, color, fontSize, maxRowWidth, fontResource); }
///// <summary> ///// 获取或设置此字符串的字体资源。 ///// </summary> //public FontResource Resource //{ // get { return this.resouce; } // set // { // if (value != this.resouce) // { // this.resouce = value; // InitTexture(this.content, this.FontSize, this.resouce); // } // } //} //public void UpdateProperties(string content, GLColor color, int fontSize, FontResource fontResource) //{ //} /// <summary> /// 用shader+VAO+组装的texture显示字符串 /// </summary> /// <param name="content">要显示的字符串</param> /// <param name="position">字符串的中心位置</param> /// <param name="color">文字颜色,默认为黑色</param> /// <param name="fontSize">字体大小,默认为32</param> /// <param name="fontResource">字体资源。默认的字体资源只支持ASCII码。</param> public PointSpriteStringElement( string content, vec3 position, GLColor color = null, int fontSize = 32, int maxRowWidth = 256, FontResource fontResource = null) { if (fontSize > 256) { throw new ArgumentException(); } this.content = content; this.position = position; if (color == null) { textColor = new vec3(0, 0, 0); } else { textColor = new vec3(color.R, color.G, color.B); } this.fontSize = fontSize; if (0 < maxRowWidth && maxRowWidth < 257) { this.maxRowWidth = maxRowWidth; } else { throw new ArgumentOutOfRangeException("max row width must between 0 and 257(not include 0 or 257)"); } if (fontResource == null) { this.resource = FontResource.Default; } else { this.resource = fontResource; } }
/// <summary> /// TODO: 这里生成的中间贴图太大,有优化的空间 /// </summary> /// <param name="content"></param> private void InitTexture(string content, int fontSize, int maxRowWidth, FontResource fontResource) { Bitmap contentBitmap = fontResource.GenerateBitmapForString(content, fontSize, maxRowWidth); // get texture's size int targetTextureWidth; { this.textureWidth = contentBitmap.Width; targetTextureWidth = contentBitmap.Width; } // scale contentBitmap to right size System.Drawing.Bitmap targetImage = contentBitmap; if (contentBitmap.Width != targetTextureWidth || contentBitmap.Height != targetTextureWidth) { // Resize the image. targetImage = (System.Drawing.Bitmap)contentBitmap.GetThumbnailImage( targetTextureWidth, targetTextureWidth, null, IntPtr.Zero); } // generate texture { // Lock the image bits (so that we can pass them to OGL). BitmapData bitmapData = targetImage.LockBits( new Rectangle(0, 0, targetImage.Width, targetImage.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); //GL.ActiveTexture(GL.GL_TEXTURE0); GL.GenTextures(1, texture); GL.BindTexture(GL.GL_TEXTURE_2D, texture[0]); GL.TexImage2D(GL.GL_TEXTURE_2D, 0, (int)GL.GL_RGBA, targetImage.Width, targetImage.Height, 0, GL.GL_BGRA, GL.GL_UNSIGNED_BYTE, bitmapData.Scan0); // Unlock the image. targetImage.UnlockBits(bitmapData); /* We require 1 byte alignment when uploading texture data */ //GL.PixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); /* Clamping to edges is important to prevent artifacts when scaling */ GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, (int)GL.GL_CLAMP_TO_EDGE); GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, (int)GL.GL_CLAMP_TO_EDGE); /* Linear filtering usually looks best for text */ GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, (int)GL.GL_LINEAR); GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, (int)GL.GL_LINEAR); } // release images { //targetImage.Save("PointSpriteFontElement-TargetImage.png"); if (targetImage != contentBitmap) { targetImage.Dispose(); } contentBitmap.Dispose(); } }
// TODO: 这里生成的中间贴图太大,有优化的空间 /// <summary> /// 为指定的字符串生成贴图。 /// </summary> /// <param name="fontResource"></param> /// <param name="content"></param> /// <param name="fontSize"></param> /// <param name="maxRowWidth"></param> /// <returns></returns> public static System.Drawing.Bitmap GenerateBitmapForString(this FontResource fontResource, string content, int fontSize, int maxRowWidth) { //fontResource.FontBitmap.Save("FontBitmap.png"); // step 1: get totalLength int totalLength = 0; { int glyphsLength = 0; for (int i = 0; i < content.Length; i++) { char c = content[i]; CharacterInfo cInfo; if (fontResource.CharInfoDict.TryGetValue(c, out cInfo)) { int glyphWidth = cInfo.width; glyphsLength += glyphWidth; } //else //{ throw new Exception(string.Format("Not support for display the char [{0}]", c)); } } //glyphsLength = (glyphsLength * this.fontSize / FontResource.Instance.FontHeight); int interval = fontResource.FontHeight / 10; if (interval < 1) { interval = 1; } totalLength = glyphsLength + interval * (content.Length - 1); } // step 2: setup contentBitmap System.Drawing.Bitmap contentBitmap = null; { int interval = fontResource.FontHeight / 10; if (interval < 1) { interval = 1; } //int totalLength = glyphsLength + interval * (content.Length - 1); int currentTextureWidth = 0; int currentWidthPos = 0; int currentHeightPos = 0; if (totalLength * fontSize > maxRowWidth * fontResource.FontHeight)// 超过1行能显示的内容 { currentTextureWidth = maxRowWidth * fontResource.FontHeight / fontSize; int lineCount = (totalLength - 1) / currentTextureWidth + 1; // 确保整篇文字的高度在贴图中间。 currentHeightPos = (currentTextureWidth - fontResource.FontHeight * lineCount) / 2; //- FontResource.Instance.FontHeight / 2; } else//只在一行内即可显示所有字符 { if (totalLength >= fontResource.FontHeight) { currentTextureWidth = totalLength; // 确保整篇文字的高度在贴图中间。 currentHeightPos = (currentTextureWidth - fontResource.FontHeight) / 2; //- FontResource.Instance.FontHeight / 2; } else { currentTextureWidth = fontResource.FontHeight; currentWidthPos = (currentTextureWidth - totalLength) / 2; //glyphsLength = fontResource.FontHeight; } } //this.textureWidth = textureWidth * this.fontSize / FontResource.Instance.FontHeight; //currentWidthPosition = currentWidthPosition * this.fontSize / FontResource.Instance.FontHeight; //currentHeightPosition = currentHeightPosition * this.fontSize / FontResource.Instance.FontHeight; contentBitmap = new Bitmap(currentTextureWidth, currentTextureWidth); Graphics gContentBitmap = Graphics.FromImage(contentBitmap); Bitmap bigBitmap = fontResource.FontBitmap; for (int i = 0; i < content.Length; i++) { char c = content[i]; CharacterInfo cInfo; if (fontResource.CharInfoDict.TryGetValue(c, out cInfo)) { if (currentWidthPos + cInfo.width > contentBitmap.Width) { currentWidthPos = 0; currentHeightPos += fontResource.FontHeight; } gContentBitmap.DrawImage(bigBitmap, new Rectangle(currentWidthPos, currentHeightPos, cInfo.width, fontResource.FontHeight), new Rectangle(cInfo.xoffset, cInfo.yoffset, cInfo.width, fontResource.FontHeight), GraphicsUnit.Pixel); currentWidthPos += cInfo.width + interval; } } gContentBitmap.Dispose(); //contentBitmap.Save("PointSpriteStringElement-contentBitmap.png"); System.Drawing.Bitmap bmp = null; if (totalLength * fontSize > maxRowWidth * fontResource.FontHeight)// 超过1行能显示的内容 { bmp = (System.Drawing.Bitmap)contentBitmap.GetThumbnailImage( maxRowWidth, maxRowWidth, null, IntPtr.Zero); } else//只在一行内即可显示所有字符 { if (totalLength >= fontResource.FontHeight) { bmp = (System.Drawing.Bitmap)contentBitmap.GetThumbnailImage( totalLength * fontSize / fontResource.FontHeight, totalLength * fontSize / fontResource.FontHeight, null, IntPtr.Zero); } else { bmp = (System.Drawing.Bitmap)contentBitmap.GetThumbnailImage( fontSize, fontSize, null, IntPtr.Zero); } } contentBitmap.Dispose(); contentBitmap = bmp; //contentBitmap.Save("PointSpriteStringElement-contentBitmap-scaled.png"); } return(contentBitmap); }