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);
        }