public void DrawString(char[] text, int startAt, int len, double x, double y)
 {
     if (this.UseSubPixelRendering)
     {
         //1. clear prev drawing result
         _aggPainter.Clear(Drawing.Color.FromArgb(0, 0, 0, 0));
         //aggPainter.Clear(Drawing.Color.White);
         //aggPainter.Clear(Drawing.Color.FromArgb(0, 0, 0, 0));
         //2. print text span into Agg Canvas
         textPrinter.DrawString(text, startAt, len, 0, 0);
         //3.copy to gl bitmap
         byte[] buffer = PixelFarm.Agg.ActualImage.GetBuffer(actualImage);
         //------------------------------------------------------
         GLBitmap glBmp = new GLBitmap(bmpWidth, bmpHeight, buffer, true);
         glBmp.IsInvert = false;
         //TODO: review font height
         canvas.DrawGlyphImageWithSubPixelRenderingTechnique(glBmp, (float)x, (float)y + 40);
         glBmp.Dispose();
     }
     else
     {
         //1. clear prev drawing result
         _aggPainter.Clear(Drawing.Color.FromArgb(0, 0, 0, 0));
         //2. print text span into Agg Canvas
         textPrinter.DrawString(text, startAt, len, 0, 0);
         //3.copy to gl bitmap
         byte[] buffer = PixelFarm.Agg.ActualImage.GetBuffer(actualImage);
         //------------------------------------------------------
         GLBitmap glBmp = new GLBitmap(bmpWidth, bmpHeight, buffer, true);
         glBmp.IsInvert = false;
         //TODO: review font height
         canvas.DrawGlyphImage(glBmp, (float)x, (float)y + 40);
         glBmp.Dispose();
     }
 }
        public void DrawString(char[] buffer, int startAt, int len, double x, double y)
        {
            int j = buffer.Length;

            //resolve font from painter?
            glyphPlans.Clear();
            _glyphLayout.Layout(_typeface, buffer, startAt, len, glyphPlans);
            float scale = _typeface.CalculateToPixelScaleFromPointSize(font.SizeInPoints);

            //--------------------------
            //TODO:
            //if (x,y) is left top
            //we need to adjust y again
            y -= (_typeface.Ascender - _typeface.Descender + _typeface.LineGap) * scale;

            int n = glyphPlans.Count;

            EnsureLoadGLBmp();
            //
            float scaleFromTexture = _finalTextureScale;

            Typography.Rendering.TextureKind textureKind = simpleFontAtlas.TextureKind;
            //--------------------------

            //TODO: review render steps
            //NOTE:
            // -glyphData.TextureXOffset => restore to original pos
            // -glyphData.TextureYOffset => restore to original pos
            // ideal_x = (float)(x + (glyph.x * scale - glyphData.TextureXOffset) * scaleFromTexture);
            // ideal_y = (float)(y + (glyph.y * scale - glyphData.TextureYOffset + srcRect.Height) * scaleFromTexture);
            //--------------------------
            GlyphPosPixelSnapKind x_snap = this.GlyphPosPixelSnapX;
            GlyphPosPixelSnapKind y_snap = this.GlyphPosPixelSnapY;
            float g_x   = 0;
            float g_y   = 0;
            int   baseY = (int)Math.Round(y);

            for (int i = 0; i < n; ++i)
            {
                GlyphPlan glyph = glyphPlans[i];
                Typography.Rendering.TextureFontGlyphData glyphData;
                if (!simpleFontAtlas.TryGetGlyphDataByCodePoint(glyph.glyphIndex, out glyphData))
                {
                    continue;
                }
                //--------------------------------------
                //TODO: review precise height in float
                //--------------------------------------
                PixelFarm.Drawing.Rectangle srcRect = ConvToRect(glyphData.Rect);
                switch (x_snap)
                {
                default: throw new NotSupportedException();

                case GlyphPosPixelSnapKind.Integer:
                {
                    g_x = (float)(x + (glyph.x * scale - glyphData.TextureXOffset) * scaleFromTexture);         //ideal x
                    int floor_x = (int)g_x;

                    //round to int 0,1
                    if (g_x - floor_x >= (1f / 2f))
                    {
                        g_x = floor_x + 1;
                    }
                    else
                    {
                        g_x = floor_x;
                    }
                }
                break;

                case GlyphPosPixelSnapKind.Half:
                {
                    g_x = (float)(x + (glyph.x * scale - glyphData.TextureXOffset) * scaleFromTexture);         //ideal x
                                                                                                                //adjust
                    int floor_x = (int)g_x;
                    //round to int 0, 0.5,1.0
                    if (g_x - floor_x >= (2f / 3f))
                    {
                        g_x = floor_x + 1;
                    }
                    else if (g_x - floor_x >= (1f / 3f))
                    {
                        g_x = floor_x + 0.5f;
                    }
                    else
                    {
                        g_x = floor_x;
                    }
                }
                break;

                case GlyphPosPixelSnapKind.None:
                    g_x = (float)(x + (glyph.x * scale - glyphData.TextureXOffset) * scaleFromTexture);
                    break;
                }
                //
                switch (y_snap)
                {
                default: throw new NotSupportedException();

                case GlyphPosPixelSnapKind.Integer:
                    //use baseY not y
                {
                    g_y = (float)((glyph.y * scale - glyphData.TextureYOffset + srcRect.Height) * scaleFromTexture);
                    int floor_y = (int)g_y;
                    //round to int 0,1
                    if (g_y - floor_y >= (1f / 2f))
                    {
                        g_y = floor_y + 1;
                    }
                    else
                    {
                        g_y = floor_y;
                    }
                    g_y = baseY + g_y;
                }
                break;

                case GlyphPosPixelSnapKind.Half:
                    //review here
                    //use baseY not y
                {
                    g_y = (float)((glyph.y * scale - glyphData.TextureYOffset + srcRect.Height) * scaleFromTexture);
                    int floor_y = (int)g_y;
                    //round to int 0, 0.5,1.0
                    if (g_y - floor_y >= (2f / 3f))
                    {
                        g_y = floor_y + 1;
                    }
                    else if (g_x - floor_y >= (1f / 3f))
                    {
                        g_y = floor_y + 0.5f;
                    }
                    else
                    {
                        g_y = floor_y;
                    }
                    g_y = baseY + g_y;
                }
                break;

                case GlyphPosPixelSnapKind.None:
                    //use Y not baseY
                    g_y = (float)(y + (glyph.y * scale - glyphData.TextureYOffset + srcRect.Height) * scaleFromTexture);
                    break;
                }

                switch (textureKind)
                {
                case Typography.Rendering.TextureKind.Msdf:

                    canvas2d.DrawSubImageWithMsdf(_glBmp,
                                                  ref srcRect,
                                                  g_x,
                                                  g_y,
                                                  scaleFromTexture);

                    break;

                case Typography.Rendering.TextureKind.AggGrayScale:

                    canvas2d.DrawSubImage(_glBmp,
                                          ref srcRect,
                                          g_x,
                                          g_y,
                                          scaleFromTexture);

                    break;

                case Typography.Rendering.TextureKind.AggSubPixel:

                    canvas2d.DrawGlyphImageWithSubPixelRenderingTechnique(_glBmp,
                                                                          ref srcRect,
                                                                          g_x,
                                                                          g_y,
                                                                          scaleFromTexture);

                    break;
                }
            }
        }