public void DrawString(char[] buffer, int startAt, int len, double left, double top)
        {
            _vboBuilder.Clear();
            _vboBuilder.SetTextureInfo(_glBmp.Width, _glBmp.Height, _glBmp.IsYFlipped, _pcx.OriginKind);
            //create temp buffer span that describe the part of a whole char buffer
            TextBufferSpan textBufferSpan = new TextBufferSpan(buffer, startAt, len);
            //ask text service to parse user input char buffer and create a glyph-plan-sequence (list of glyph-plan)
            //with specific request font
            GlyphPlanSequence glyphPlanSeq = _textServices.CreateGlyphPlanSeq(ref textBufferSpan, _font);
            float             px_scale     = _px_scale;
            //--------------------------
            //TODO:
            //if (x,y) is left top
            //we need to adjust y again

            float scaleFromTexture = _font.SizeInPoints / _fontAtlas.OriginalFontSizePts;

            TextureKind textureKind = _fontAtlas.TextureKind;

            float g_left   = 0;
            float g_top    = 0;
            int   baseLine = (int)Math.Round((float)top + _font.AscentInPixels);
            int   bottom   = (int)Math.Round((float)top + _font.AscentInPixels - _font.DescentInPixels);

            float acc_x = 0; //local accumulate x
            float acc_y = 0; //local accumulate y

#if DEBUG
            if (s_dbugShowMarkers)
            {
                if (s_dbugShowGlyphTexture)
                {
                    //show original glyph texture at top
                    _pcx.DrawImage(_glBmp, 0, 0);
                }
                //draw red-line-marker for baseLine
                _painter.StrokeColor = Color.Red;
                _painter.DrawLine(left, baseLine, left + 200, baseLine);
                //
                //draw magenta-line-marker for bottom line
                _painter.StrokeColor = Color.Magenta;
                int bottomLine = (int)Math.Round((float)top + _font.LineSpacingInPixels);
                _painter.DrawLine(left, bottomLine, left + 200, bottomLine);
                //draw blue-line-marker for top line
                _painter.StrokeColor = Color.Blue;
                _painter.DrawLine(0, top, left + 200, top);
            }

            DrawingTechnique = s_dbugDrawTechnique; //for debug only
            UseVBO           = s_dbugUseVBO;        //for debug only
#endif

            if (textureKind == TextureKind.Msdf)
            {
                DrawingTechnique = GlyphTexturePrinterDrawingTechnique.Msdf;
            }


            //----------
            int seqLen = glyphPlanSeq.Count;
            for (int i = 0; i < seqLen; ++i)
            {
                UnscaledGlyphPlan glyph = glyphPlanSeq[i];
                Typography.Rendering.TextureGlyphMapData glyphData;
                if (!_fontAtlas.TryGetGlyphMapData(glyph.glyphIndex, out glyphData))
                {
                    //if no glyph data, we should render a missing glyph ***
                    continue;
                }
                //--------------------------------------
                //TODO: review precise height in float
                //--------------------------------------

                //paint src rect
                //temp fix, glyph texture img is not flipped
                //but the associate info is flipped => so
                //we need remap exact Y from the image

                Rectangle srcRect =
                    new Rectangle(glyphData.Left,
                                  _glBmp.Height - (glyphData.Top + glyphData.Height),
                                  glyphData.Width,
                                  glyphData.Height);

                //offset length from 'base-line'
                float x_offset = acc_x + (float)Math.Round(glyph.OffsetX * px_scale - glyphData.TextureXOffset * scaleFromTexture);
                float y_offset = acc_y + (float)Math.Round(glyph.OffsetY * px_scale - glyphData.TextureYOffset * scaleFromTexture) + srcRect.Height; //***

                //NOTE:
                // -glyphData.TextureXOffset => restore to original pos
                // -glyphData.TextureYOffset => restore to original pos
                //--------------------------

                g_left = (float)(left + x_offset);
                g_top  = (float)(bottom - y_offset); //***

                acc_x += (float)Math.Round(glyph.AdvanceX * px_scale);
                g_top  = (float)Math.Floor(g_top);//adjust to integer num ***

#if DEBUG
                if (s_dbugShowMarkers)
                {
                    if (s_dbugShowGlyphTexture)
                    {
                        //draw yellow-rect-marker on original texture
                        _painter.DrawRectangle(srcRect.X, srcRect.Y, srcRect.Width, srcRect.Height, Color.Yellow);
                    }

                    //draw debug-rect box at target glyph position
                    _painter.DrawRectangle(g_left, g_top, srcRect.Width, srcRect.Height, Color.Black);
                    _painter.StrokeColor = Color.Blue; //restore
                }


                //System.Diagnostics.Debug.WriteLine(
                //    "ds:" + buffer[0] + "o=(" + left + "," + top + ")" +
                //    "g=(" + g_left + "," + g_top + ")" + "srcRect=" + srcRect);
#endif

                if (UseVBO)
                {
                    _vboBuilder.WriteVboToList(
                        ref srcRect,
                        g_left, g_top, scaleFromTexture);
                }
                else
                {
                    switch (DrawingTechnique)
                    {
                    case GlyphTexturePrinterDrawingTechnique.Msdf:
                        _pcx.DrawSubImageWithMsdf(_glBmp,
                                                  ref srcRect,
                                                  g_left,
                                                  g_top,
                                                  scaleFromTexture);
                        break;

                    case GlyphTexturePrinterDrawingTechnique.Stencil:
                        //stencil gray scale with fill-color
                        _pcx.DrawGlyphImageWithStecil(_glBmp,
                                                      ref srcRect,
                                                      g_left,
                                                      g_top,
                                                      scaleFromTexture);
                        break;

                    case GlyphTexturePrinterDrawingTechnique.Copy:
                        _pcx.DrawSubImage(_glBmp,
                                          ref srcRect,
                                          g_left,
                                          g_top,
                                          1);
                        break;

                    case GlyphTexturePrinterDrawingTechnique.LcdSubPixelRendering:
                        _pcx.DrawGlyphImageWithSubPixelRenderingTechnique2_GlyphByGlyph(
                            _glBmp,
                            ref srcRect,
                            g_left,
                            g_top,
                            1);
                        break;
                    }
                }
            }
            //-------------------------------------------
            //

            if (UseVBO)
            {
                switch (DrawingTechnique)
                {
                case GlyphTexturePrinterDrawingTechnique.Copy:
                    _pcx.DrawGlyphImageWithCopy_VBO(_glBmp, _vboBuilder);
                    break;

                case GlyphTexturePrinterDrawingTechnique.LcdSubPixelRendering:
                    _pcx.DrawGlyphImageWithSubPixelRenderingTechnique3_DrawElements(_glBmp, _vboBuilder);
                    break;

                case GlyphTexturePrinterDrawingTechnique.Stencil:
                    _pcx.DrawGlyphImageWithStecil_VBO(_glBmp, _vboBuilder);
                    break;

                case GlyphTexturePrinterDrawingTechnique.Msdf:
                    _pcx.DrawImagesWithMsdf_VBO(_glBmp, _vboBuilder);
                    break;
                }

                _vboBuilder.Clear();
            }
        }
Ejemplo n.º 2
0
        public override void DrawFromGlyphPlans(GlyphPlanSequence seq, int startAt, int len, float left, float top)
        {
            if (StartDrawOnLeftTop)
            {
                //version 2
                //offset y down
                top += this.FontLineSpacingPx;
            }

            float fontSizePoint = this.FontSizeInPoints;
            float scale         = _currentTypeface.CalculateScaleToPixelFromPointSize(fontSizePoint);

            //4. render each glyph
            float ox = _painter.OriginX;
            float oy = _painter.OriginY;


            Typography.OpenFont.Tables.COLR colrTable = _currentTypeface.COLRTable;
            Typography.OpenFont.Tables.CPAL cpalTable = _currentTypeface.CPALTable;
            bool hasColorGlyphs = (colrTable != null) && (cpalTable != null);

            //---------------------------------------------------
            _glyphMeshStore.SetHintTechnique(this.HintTechnique);
            _glyphMeshStore.SetFont(_currentTypeface, fontSizePoint);
            _glyphMeshStore.SimulateOblique = this.SimulateSlant;
            //---------------------------------------------------


            if (_currentTypeface.HasSvgTable())
            {
                _glyphSvgStore.SetCurrentTypeface(_currentTypeface);
                int seqLen = seq.Count;
                if (len > seqLen)
                {
                    len = seqLen;
                }

                var snapToPx = new GlyphPlanSequenceSnapPixelScaleLayout(seq, startAt, len, scale);
                while (snapToPx.Read())
                {
                    _painter.SetOrigin((float)Math.Round(left + snapToPx.ExactX) + 0.33f, (float)Math.Floor(top + snapToPx.ExactY));

                    GlyphBitmap glyphBmp = _glyphSvgStore.GetGlyphBitmap(snapToPx.CurrentGlyphIndex);
                    //how to draw the image
                    //1.
                    if (glyphBmp != null)
                    {
                        _painter.DrawImage(glyphBmp.Bitmap);
                    }
                }
            }
            else if (_currentTypeface.IsBitmapFont)
            {
                //check if we have exported all the glyph bitmap
                //to some 'ready' form?
                //if not then create it
                _glyphBitmapStore.SetCurrentTypeface(_currentTypeface);

                int seqLen = seq.Count;

                if (len > seqLen)
                {
                    len = seqLen;
                }

                var snapToPx = new GlyphPlanSequenceSnapPixelScaleLayout(seq, startAt, len, scale);
                while (snapToPx.Read())
                {
                    _painter.SetOrigin((float)Math.Round(left + snapToPx.ExactX) + 0.33f, (float)Math.Floor(top + snapToPx.ExactY));
                    GlyphBitmap glyphBmp = _glyphBitmapStore.GetGlyphBitmap(snapToPx.CurrentGlyphIndex);
                    //how to draw the image
                    //1.
                    _painter.DrawImage(glyphBmp.Bitmap);
                }
            }
            else
            {
                if (!hasColorGlyphs)
                {
                    bool          savedUseLcdMode   = _painter.UseSubPixelLcdEffect; //save,restore later
                    RenderQuality savedRederQuality = _painter.RenderQuality;
                    _painter.RenderQuality        = RenderQuality.HighQuality;
                    _painter.UseSubPixelLcdEffect = true;

                    int seqLen = seq.Count;

                    if (len > seqLen)
                    {
                        len = seqLen;
                    }

                    var snapToPx = new GlyphPlanSequenceSnapPixelScaleLayout(seq, startAt, len, scale);
                    while (snapToPx.Read())
                    {
                        _painter.SetOrigin((float)Math.Round(left + snapToPx.ExactX) + 0.33f, (float)Math.Floor(top + snapToPx.ExactY));
                        _painter.Fill(_glyphMeshStore.GetGlyphMesh(snapToPx.CurrentGlyphIndex));
                    }

                    //restore
                    _painter.RenderQuality        = savedRederQuality;
                    _painter.UseSubPixelLcdEffect = savedUseLcdMode;
                }
                else
                {
                    //-------------
                    //this glyph has color information
                    //-------------
                    Color originalFillColor = _painter.FillColor;
                    int   seqLen            = seq.Count;

                    if (len > seqLen)
                    {
                        len = seqLen;
                    }

                    var snapToPx = new GlyphPlanSequenceSnapPixelScaleLayout(seq, startAt, len, scale);
                    while (snapToPx.Read())
                    {
                        _painter.SetOrigin((float)Math.Round(left + snapToPx.ExactX), (float)Math.Floor(top + snapToPx.ExactY));

                        ushort colorLayerStart;
                        if (colrTable.LayerIndices.TryGetValue(snapToPx.CurrentGlyphIndex, out colorLayerStart))
                        {
                            //TODO: optimize this
                            //we found color info for this glyph
                            ushort colorLayerCount = colrTable.LayerCounts[snapToPx.CurrentGlyphIndex];
                            byte   r, g, b, a;
                            for (int c = colorLayerStart; c < colorLayerStart + colorLayerCount; ++c)
                            {
                                ushort gIndex = colrTable.GlyphLayers[c];

                                int palette = 0;                                              // FIXME: assume palette 0 for now
                                cpalTable.GetColor(
                                    cpalTable.Palettes[palette] + colrTable.GlyphPalettes[c], //index
                                    out r, out g, out b, out a);
                                //-----------
                                _painter.FillColor = new Color(r, g, b);//? a component
                                _painter.Fill(_glyphMeshStore.GetGlyphMesh(gIndex));
                            }
                        }
                        else
                        {
                            //-----------------------------------
                            //TODO: review here ***
                            //PERFORMANCE revisit here
                            //if we have create a vxs we can cache it for later use?
                            //-----------------------------------
                            _painter.Fill(_glyphMeshStore.GetGlyphMesh(snapToPx.CurrentGlyphIndex));
                        }
                    }

                    _painter.FillColor = originalFillColor; //restore color
                }
            }
            //restore prev origin
            _painter.SetOrigin(ox, oy);
        }
Ejemplo n.º 3
0
        public override void DrawFromGlyphPlans(GlyphPlanSequence glyphPlanSeq, int startAt, int len, float left, float top)
        {
            Typeface typeface = _textServices.ResolveTypeface(_font);

            float scale = typeface.CalculateScaleToPixelFromPointSize(_font.SizeInPoints);
            int   recommendLineSpacing = (int)_font.LineSpacingInPixels;
            //--------------------------
            //TODO:
            //if (x,y) is left top
            //we need to adjust y again

            //

            TextureKind textureKind = _fontAtlas.TextureKind;

            float gx    = 0;
            float gy    = 0;
            int   baseY = (int)Math.Round(top);


            float acc_x = 0;
            float acc_y = 0;

            int lineHeight = (int)_font.LineSpacingInPixels;                              //temp

            PixelBlender32 prevPxBlender = _painter.DestBitmapBlender.OutputPixelBlender; //save

            _painter.DestBitmapBlender.OutputPixelBlender = _maskPixelBlenderPerCompo;    //change to new blender

            bool fillGlyphByGlyph = true;

            if (fillGlyphByGlyph)
            {
                //test...
                //fill glyph-by-glyh

                var aaTech = this.AntialiasTech;
                int seqLen = glyphPlanSeq.Count;


                for (int i = 0; i < seqLen; ++i)
                {
                    UnscaledGlyphPlan   unscaledGlyphPlan = glyphPlanSeq[i];
                    TextureGlyphMapData glyphData;
                    if (!_fontAtlas.TryGetGlyphMapData(unscaledGlyphPlan.glyphIndex, out glyphData))
                    {
                        //if no glyph data, we should render a missing glyph ***
                        continue;
                    }
                    //--------------------------------------
                    //TODO: review precise height in float
                    //--------------------------------------
                    int srcX, srcY, srcW, srcH;
                    glyphData.GetRect(out srcX, out srcY, out srcW, out srcH);

                    float ngx = acc_x + (float)Math.Round(unscaledGlyphPlan.OffsetX * scale);
                    float ngy = acc_y + (float)Math.Round(unscaledGlyphPlan.OffsetY * scale);
                    //NOTE:
                    // -glyphData.TextureXOffset => restore to original pos
                    // -glyphData.TextureYOffset => restore to original pos
                    //--------------------------

                    //if (glyphData.TextureXOffset != 0)
                    //{
                    //}

                    gx = (float)(left + (ngx - glyphData.TextureXOffset)); //ideal x
                    gy = (float)(top + (ngy + glyphData.TextureYOffset - srcH + lineHeight));

                    acc_x += (float)Math.Round(unscaledGlyphPlan.AdvanceX * scale);
                    gy     = (float)Math.Floor(gy);// + lineHeight;

                    //clear with solid black color
                    //_maskBufferPainter.Clear(Color.Black);
                    //clear mask buffer at specific pos
                    _maskBufferPainter.FillRect(gx - 1, gy - 1, srcW + 2, srcH + 2, Color.Black);
                    //draw 'stencil' glyph on mask-buffer
                    _maskBufferPainter.DrawImage(_fontBmp, gx, gy, srcX, _fontBmp.Height - (srcY + srcH), srcW, srcH);

                    switch (aaTech)
                    {
                    default:
                    {
                        //select component to render this need to render 3 times for lcd technique
                        //1. B
                        _maskPixelBlenderPerCompo.SelectedMaskComponent      = PixelBlenderColorComponent.B;
                        _maskPixelBlenderPerCompo.EnableOutputColorComponent = EnableOutputColorComponent.B;
                        _painter.FillRect(gx + 1, gy, srcW, srcH);
                        //2. G
                        _maskPixelBlenderPerCompo.SelectedMaskComponent      = PixelBlenderColorComponent.G;
                        _maskPixelBlenderPerCompo.EnableOutputColorComponent = EnableOutputColorComponent.G;
                        _painter.FillRect(gx + 1, gy, srcW, srcH);
                        //3. R
                        _maskPixelBlenderPerCompo.SelectedMaskComponent      = PixelBlenderColorComponent.R;
                        _maskPixelBlenderPerCompo.EnableOutputColorComponent = EnableOutputColorComponent.R;
                        _painter.FillRect(gx + 1, gy, srcW, srcH);
                    }
                    break;

                    case AntialiasTechnique.GreyscaleStencil:
                    {
                        //fill once
                        //we choose greeh channel (middle)
                        _maskPixelBlenderPerCompo.SelectedMaskComponent      = PixelBlenderColorComponent.G;
                        _maskPixelBlenderPerCompo.EnableOutputColorComponent = EnableOutputColorComponent.EnableAll;
                        _painter.FillRect(gx + 1, gy, srcW, srcH);
                    }
                    break;
                    }
                }
            }
            else
            {
                //clear entire line
                _maskBufferPainter.FillRect(gx - 1, gy - 1, _maskBufferPainter.Width - gx + 2, lineHeight + 2, Color.Black);

                bool  isFirst = true;
                int   startX = 0, startY = 0;
                float lenW = 0;
                float lenH = 0;

                int seqLen = glyphPlanSeq.Count;
                for (int i = 0; i < seqLen; ++i)
                {
                    UnscaledGlyphPlan glyph = glyphPlanSeq[i];

                    TextureGlyphMapData glyphData;
                    if (!_fontAtlas.TryGetGlyphMapData(glyph.glyphIndex, out glyphData))
                    {
                        //if no glyph data, we should render a missing glyph ***
                        continue;
                    }
                    //--------------------------------------
                    //TODO: review precise height in float
                    //--------------------------------------
                    int srcX, srcY, srcW, srcH;
                    glyphData.GetRect(out srcX, out srcY, out srcW, out srcH);

                    float ngx = acc_x + (float)Math.Round(glyph.OffsetX * scale);
                    float ngy = acc_y + (float)Math.Round(glyph.OffsetY * scale);
                    //NOTE:
                    // -glyphData.TextureXOffset => restore to original pos
                    // -glyphData.TextureYOffset => restore to original pos
                    //--------------------------
                    gx = (float)(left + (ngx - glyphData.TextureXOffset)); //ideal x
                    gy = (float)(top + (ngy - glyphData.TextureYOffset - srcH + lineHeight));

                    acc_x += (float)Math.Round(glyph.AdvanceX * scale);
                    gy     = (float)Math.Floor(gy) + lineHeight;

                    if (isFirst)
                    {
                        startX  = (int)gx;
                        startY  = (int)gy;
                        isFirst = false;
                    }

                    _maskBufferPainter.DrawImage(_fontBmp, gx + 1, gy, srcX, _fontBmp.Height - (srcY), srcW + 1, srcH);

                    lenW = gx + srcW;
                    if (srcH > lenH)
                    {
                        lenH = srcH;
                    }
                }
                //--------------------------
                //fill color on 'stencil' mask
                {
                    //select component to render this need to render 3 times for lcd technique
                    //1. B
                    _maskPixelBlenderPerCompo.SelectedMaskComponent      = PixelBlenderColorComponent.B;
                    _maskPixelBlenderPerCompo.EnableOutputColorComponent = EnableOutputColorComponent.B;
                    _painter.FillRect(startX + 1, startY, lenW, lenH);
                    //2. G
                    _maskPixelBlenderPerCompo.SelectedMaskComponent      = PixelBlenderColorComponent.G;
                    _maskPixelBlenderPerCompo.EnableOutputColorComponent = EnableOutputColorComponent.G;
                    _painter.FillRect(startX + 1, startY, lenW, lenH);
                    //3. R
                    _maskPixelBlenderPerCompo.SelectedMaskComponent      = PixelBlenderColorComponent.R;
                    _maskPixelBlenderPerCompo.EnableOutputColorComponent = EnableOutputColorComponent.R;
                    _painter.FillRect(startX + 1, startY, lenW, lenH);
                }
            }

            //
            _painter.DestBitmapBlender.OutputPixelBlender = prevPxBlender;//restore back
        }
Ejemplo n.º 4
0
        private void button1_Click(object sender, EventArgs e)
        {
            selectedTextPrinter                   = _devVxsTextPrinter;
            selectedTextPrinter.Typeface          = _basicOptions.Typeface;
            selectedTextPrinter.FontSizeInPoints  = _basicOptions.FontSizeInPoints;
            selectedTextPrinter.ScriptLang        = _basicOptions.ScriptLang;
            selectedTextPrinter.PositionTechnique = _basicOptions.PositionTech;
            selectedTextPrinter.HintTechnique     = HintTechnique.None;
            selectedTextPrinter.EnableLigature    = true;
            _devVxsTextPrinter.UpdateGlyphLayoutSettings();

            //-------
            var editableTextBlockLayoutEngine = new EditableTextBlockLayoutEngine();

            editableTextBlockLayoutEngine.DefaultTypeface = _basicOptions.Typeface;
            editableTextBlockLayoutEngine.FontSizeInPts   = _basicOptions.FontSizeInPoints;
            editableTextBlockLayoutEngine.LoadText("ABCD\r\n   EFGH!");
            editableTextBlockLayoutEngine.DoLayout();

            //then we render the output to the screen
            //see UpdateRenderOutput() code
            //clear previous draw
            //----------------

            //-------------
            painter.Clear(PixelFarm.Drawing.Color.White);
            painter.UseSubPixelRendering           = false;
            painter.FillColor                      = PixelFarm.Drawing.Color.Black;
            _devVxsTextPrinter.TargetCanvasPainter = painter;

            List <EditableTextLine> textlines = editableTextBlockLayoutEngine.UnsafeGetEditableTextLine();
            //render eachline with painter
            int lineCount = textlines.Count;

            float x           = 0;
            int   y           = 200;
            int   lineSpacing = (int)_devVxsTextPrinter.FontLineSpacingPx;

            for (int i = 0; i < lineCount; ++i)
            {
                EditableTextLine line = textlines[i];
                List <IRun>      runs = line.UnsageGetTextRunList();
                int runCount          = runs.Count;

                for (int r = 0; r < runCount; ++r)
                {
                    IRun    run     = runs[r];
                    TextRun textRun = run as TextRun;
                    if (textRun == null)
                    {
                        continue;
                    }
                    //
                    GlyphPlanSequence seq = textRun.GetGlyphPlanSeq();
                    _devVxsTextPrinter.DrawFromGlyphPlans(
                        seq.UnsafeGetInteralGlyphPlanList(),
                        seq.startAt,
                        seq.len,
                        x, y);
                    x += run.Width;
                    y -= lineSpacing; //next line?
                }
                x = 0;                //reset at newline
            }
            //----------

            //use this util to copy image from Agg actual image to System.Drawing.Bitmap
            PixelFarm.Agg.Imaging.BitmapHelper.CopyToGdiPlusBitmapSameSize(painter.Graphics.DestActualImage, winBmp);
            //----------------
            //copy from Agg's memory buffer to gdi
            //PixelFarm.Agg.Imaging.BitmapHelper.CopyToGdiPlusBitmapSameSize(destImg, winBmp);
            g.Clear(Color.White);
            g.DrawImage(winBmp, new Point(10, 0));
        }
Ejemplo n.º 5
0
 public override void DrawFromGlyphPlans(GlyphPlanSequence glyphPlanList, int startAt, int len, float x, float y)
 {
     throw new System.NotImplementedException();
 }
Ejemplo n.º 6
0
        public void DrawString(Painter p, char[] buffer, int startAt, int len, double x, double y)
        {
            //if (_stencilBmp == null)
            //{
            //    //create a stencil bmp
            //    _stencilBmp = new ActualBitmap(p.Width, p.Height);
            //    _stencilBlender = new PixelProcessing.SubBitmapBlender(_stencilBmp, new PixelProcessing.PixelBlenderBGRA());
            //    _backPainter = AggPainter.Create(_stencilBmp);
            //    //------
            //}

            int j = buffer.Length;
            //create temp buffer span that describe the part of a whole char buffer
            TextBufferSpan textBufferSpan = new TextBufferSpan(buffer, startAt, len);

            //ask text service to parse user input char buffer and create a glyph-plan-sequence (list of glyph-plan)
            //with specific request font
            GlyphPlanSequence glyphPlanSeq = _textServices.CreateGlyphPlanSeq(ref textBufferSpan, _font);

            Typeface typeface = _textServices.ResolveTypeface(_font);
            float    scale    = typeface.CalculateScaleToPixelFromPointSize(_font.SizeInPoints);

            int recommendLineSpacing = (int)_font.LineSpacingInPixels;

            //--------------------------
            //TODO:
            //if (x,y) is left top
            //we need to adjust y again
            y -= _font.LineSpacingInPixels;

            //
            float       scaleFromTexture = _finalTextureScale;
            TextureKind textureKind      = _fontAtlas.TextureKind;

            float g_x   = 0;
            float g_y   = 0;
            int   baseY = (int)Math.Round(y);

            //-------------------------------------
            //load texture
            //_pcx.LoadTexture1(_glBmp);
            //-------------------------------------


            float acc_x = 0;
            float acc_y = 0;

            p.DrawImage(_fontBmp, 100, 100);

            int seqLen = glyphPlanSeq.Count;

            for (int i = 0; i < seqLen; ++i)
            {
                UnscaledGlyphPlan   glyph = glyphPlanSeq[i];
                TextureGlyphMapData glyphData;
                if (!_fontAtlas.TryGetGlyphMapData(glyph.glyphIndex, out glyphData))
                {
                    //if no glyph data, we should render a missing glyph ***
                    continue;
                }
                //--------------------------------------
                //TODO: review precise height in float
                //--------------------------------------
                int srcX, srcY, srcW, srcH;
                glyphData.GetRect(out srcX, out srcY, out srcW, out srcH);

                float ngx = acc_x + (float)Math.Round(glyph.OffsetX * scale);
                float ngy = acc_y + (float)Math.Round(glyph.OffsetY * scale);
                //NOTE:
                // -glyphData.TextureXOffset => restore to original pos
                // -glyphData.TextureYOffset => restore to original pos
                //--------------------------
                g_x = (float)(x + (ngx - glyphData.TextureXOffset) * scaleFromTexture); //ideal x
                g_y = (float)(y + (ngy - glyphData.TextureYOffset + srcH) * scaleFromTexture);

                acc_x += (float)Math.Round(glyph.AdvanceX * scale);
                //g_x = (float)Math.Round(g_x);
                g_y = (float)Math.Floor(g_y);

                //p.RenderQuality = RenderQuality.Fast;

                //*** the atlas is inverted so...
                //p.DrawImage(_fontBmp, g_x, g_y, srcX, _fontBmp.Height - (srcY), srcW, srcH);
                //p.DrawImage(_fontBmp, g_x, g_y);

                //1. draw to back buffer
                //_backPainter.DrawImage(_fontBmp, g_x, g_y, srcX, _fontBmp.Height - (srcY), srcW, srcH);

                //2. then copy content to this

                //p.DrawImage(_stencilBmp, 100, 100);
                p.DrawImage(_fontBmp, g_x, g_y, srcX, _fontBmp.Height - (srcY + srcH), srcW, srcH);
                switch (textureKind)
                {
                default:
                    break;

                case TextureKind.StencilLcdEffect:
                {
                }
                break;
                }



                //copy some part from the bitmap
                //switch (textureKind)
                //{
                //    case TextureKind.Msdf:
                //        _pcx.DrawSubImageWithMsdf(_glBmp,
                //            ref srcRect,
                //            g_x,
                //            g_y,
                //            scaleFromTexture);
                //        break;
                //    case TextureKind.StencilGreyScale:
                //        //stencil gray scale with fill-color
                //        _pcx.DrawGlyphImageWithStecil(_glBmp,
                //         ref srcRect,
                //            g_x,
                //            g_y,
                //            scaleFromTexture);
                //        break;
                //    case TextureKind.Bitmap:
                //        _pcx.DrawSubImage(_glBmp,
                //         ref srcRect,
                //            g_x,
                //            g_y,
                //            scaleFromTexture);
                //        break;
                //    case TextureKind.StencilLcdEffect:
                //        _pcx.WriteVboToList(
                //          _vboBufferList,
                //          _indexList,
                //          ref srcRect,
                //          g_x,
                //          g_y,
                //          scaleFromTexture);

                //        break;
                //}
            }
            //-------
            //we create vbo first
            //then render
        }