Beispiel #1
0
        Size CalculateDrawingStringSize(int length)
        {
            if (!_content_unparsed)
            {
                //the content is parsed ***

                if (_mybuffer.Length == length)
                {
                    return(this.Size);
                }
                else
                {
                    //ca
                    int total = 0;
                    if (_outputUserCharAdvances != null)
                    {
                        for (int i = 0; i < length; ++i)
                        {
                            total += _outputUserCharAdvances[i];
                        }
                    }
                    return(new Size(total, (int)Math.Round(Root.TextServices.MeasureBlankLineHeight(GetFont()))));
                }
            }

            var textBufferSpan = new TextBufferSpan(_mybuffer, 0, length);

            return(this.Root.TextServices.MeasureString(ref textBufferSpan, GetFont()));
        }
Beispiel #2
0
        //
        public void CalculateUserCharGlyphAdvancePos(ref TextBufferSpan textBufferSpan,
                                                     ILineSegmentList lineSegs,
                                                     RequestFont font,
                                                     int[] outputUserInputCharAdvance, out int outputTotalW, out int lineHeight)
        {
            //layout
            //from font
            //resolve for typeface
            //
            Typeface typeface = ResolveTypeface(font);

            _txtServices.SetCurrentFont(typeface, font.SizeInPoints);


            MyLineSegmentList mylineSegs = (MyLineSegmentList)lineSegs;
            float             scale      = typeface.CalculateScaleToPixelFromPointSize(font.SizeInPoints);

            outputTotalW = 0;
            int j   = mylineSegs.Count;
            int pos = 0; //start at 0

            _reusableTextBuffer.SetRawCharBuffer(textBufferSpan.GetRawCharBuffer());

            for (int i = 0; i < j; ++i)
            {
                //get each segment
                MyLineSegment lineSeg = (MyLineSegment)mylineSegs.GetSegment(i);
                //each line seg may has different script lang
                _txtServices.CurrentScriptLang = lineSeg.scriptLang;
                //
                //CACHING ...., reduce number of GSUB/GPOS
                //
                //we cache used line segment for a while
                //we ask for caching context for a specific typeface and font size
                GlyphPlanSequence seq = _txtServices.GetUnscaledGlyphPlanSequence(_reusableTextBuffer,
                                                                                  lineSeg.StartAt,
                                                                                  lineSeg.Length);

                int seqLen = seq.Count;

                for (int s = 0; s < seqLen; ++s)
                {
                    UnscaledGlyphPlan glyphPlan = seq[s];

                    double actualAdvX = glyphPlan.AdvanceX;

                    outputTotalW +=
                        outputUserInputCharAdvance[pos + glyphPlan.input_cp_offset] +=
                            (int)Math.Round(actualAdvX * scale);
                }
                pos += lineSeg.Length;
            }

            //

            lineHeight = (int)Math.Round(typeface.CalculateRecommendLineSpacing() * scale);

            _reusableTextBuffer.SetRawCharBuffer(null);
        }
Beispiel #3
0
        public Size MeasureString(ref TextBufferSpan textBufferSpan, RequestFont font)
        {
            Typeface typeface = ResolveTypeface(font);

            _txtServices.SetCurrentFont(typeface, font.SizeInPoints);
            _txtServices.MeasureString(textBufferSpan.GetRawCharBuffer(), textBufferSpan.start, textBufferSpan.len, out int w, out int h);
            return(new Size(w, h));
        }
        public void MeasureString(char[] buffer, int startAt, int len, out int w, out int h)
        {
            TextBufferSpan textBufferSpan = new TextBufferSpan(buffer, startAt, len);
            Size           s = _textServices.MeasureString(ref textBufferSpan, _painter.CurrentFont);

            w = s.Width;
            h = s.Height;
        }
Beispiel #5
0
        void InternalDrawString(char[] buffer, int startAt, int len, float x, float y)
        {
            UpdateGlyphLayoutSettings();
            //unscale layout, with design unit scale
            TextBufferSpan    buffSpan     = new TextBufferSpan(buffer, startAt, len);
            GlyphPlanSequence glyphPlanSeq = _textServices.CreateGlyphPlanSeq(ref buffSpan, _reqFont);

            DrawFromGlyphPlans(glyphPlanSeq, x, y);
        }
Beispiel #6
0
 public void CalculateUserCharGlyphAdvancePos(ref TextBufferSpan textBufferSpan,
                                              ILineSegmentList lineSegs,
                                              RequestFont font,
                                              int[] glyphXAdvances,
                                              out int outputTotalW,
                                              out int outputLineHeight)
 {
     throw new NotImplementedException();
 }
Beispiel #7
0
        public void MeasureString(ref TextBufferSpan textBufferSpan, RequestFont font, int limitWidth, out int charFit, out int charFitWidth)
        {
            Typeface typeface = ResolveTypeface(font);

            _txtServices.SetCurrentFont(typeface, font.SizeInPoints);

            charFit = 0;
            _txtServices.MeasureString(textBufferSpan.GetRawCharBuffer(), textBufferSpan.start, textBufferSpan.len, limitWidth, out charFit, out charFitWidth);
        }
        void InternalDrawString(char[] buffer, int startAt, int len, float x, float y)
        {
            //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
            DrawFromGlyphPlans(_textServices.CreateGlyphPlanSeq(ref textBufferSpan, _font), startAt, len, x, y);
        }
Beispiel #9
0
        public GlyphPlanSequence CreateGlyphPlanSeq(ref TextBufferSpan textBufferSpan, RequestFont font)
        {
            Typeface typeface = ResolveTypeface(font);

            _txtServices.SetCurrentFont(typeface, font.SizeInPoints);

            _reusableTextBuffer.SetRawCharBuffer(textBufferSpan.GetRawCharBuffer());

            return(_txtServices.GetUnscaledGlyphPlanSequence(_reusableTextBuffer, textBufferSpan.start, textBufferSpan.len));
        }
Beispiel #10
0
        public void MeasureString(char[] buffer, int startAt, int len, out int w, out int h)
        {
            UpdateGlyphLayoutSettings();
            _glyphMeshStore.SetFont(_currentTypeface, this.FontSizeInPoints);
            _glyphMeshStore.SimulateOblique = this.SimulateSlant;
            TextBufferSpan textBuffSpan = new TextBufferSpan(buffer, startAt, len);
            Size           s            = _textServices.MeasureString(ref textBuffSpan, _painter.CurrentFont);

            w = s.Width;
            h = s.Height;
        }
Beispiel #11
0
        public override void UpdateRunWidth()
        {
            ITextService txServices = Root.TextServices;
            Size         size;

            if (IsLineBreak)
            {
                //TODO: review here
                //we should not store this as a text run
                //if this is a linebreak it should be encoded at the end of this visual line
                size = new Size(0, (int)Math.Round(txServices.MeasureBlankLineHeight(GetFont())));
                _outputUserCharAdvances = null;
            }
            else
            {
                //TODO: review here again
                //1. after GSUB process, output glyph may be more or less
                //than original input char buffer(mybuffer)

                if (txServices.SupportsWordBreak)
                {
                    var textBufferSpan = new TextBufferSpan(_mybuffer);
                    int len            = _mybuffer.Length;
                    if (_content_unparsed)
                    {
                        //parse the content first
                        _lineSegs = txServices.BreakToLineSegments(ref textBufferSpan);
                    }
                    //
                    _content_unparsed = false;
                    //output glyph position
                    _outputUserCharAdvances = new int[len];

                    int outputTotalW, outputLineHeight;
                    txServices.CalculateUserCharGlyphAdvancePos(ref textBufferSpan, _lineSegs, GetFont(),
                                                                _outputUserCharAdvances, out outputTotalW, out outputLineHeight);
                    size = new Size(outputTotalW, outputLineHeight);
                }
                else
                {
                    _content_unparsed = false;
                    int len = _mybuffer.Length;
                    _outputUserCharAdvances = new int[len];
                    int outputTotalW, outputLineHeight;
                    var textBufferSpan = new TextBufferSpan(_mybuffer);
                    txServices.CalculateUserCharGlyphAdvancePos(ref textBufferSpan, GetFont(),
                                                                _outputUserCharAdvances, out outputTotalW, out outputLineHeight);
                    size = new Size(outputTotalW, outputLineHeight);
                }
            }
            //---------
            this.SetSize(size.Width, size.Height);
            MarkHasValidCalculateSize();
        }
Beispiel #12
0
        public Typeface ResolveTypeface(RequestFont font)
        {
            //from user's request font
            //resolve to actual Typeface
            //get data from...
            //cache level-1 (attached inside the request font)
            Typeface typeface = PixelFarm.Drawing.Internal.RequestFontCacheAccess.GetActualFont <Typeface>(font, _system_id);

            if (typeface != null)
            {
                return(typeface);
            }
            //
            //cache level-2 (stored in this Ifonts)
            if (!_resolvedTypefaceCache.TryGetValue(font.FontKey, out typeface))
            {
                //not found ask the typeface store to load that font
                //....
                typeface = _txtServices.GetTypeface(font.Name, font.Style.ConvToInstalledFontStyle());
                if (typeface == null)
                {
                    throw new NotSupportedException();
                }
                //
                //cache here (level-1)
                _resolvedTypefaceCache.Add(font.FontKey, typeface);
            }
            //and cache into level-0

            float pxSize = Typeface.ConvPointsToPixels(font.SizeInPoints);

            float pxscale = typeface.CalculateScaleToPixelFromPointSize(font.SizeInPoints);

            float recommedLineSpacingInPx = typeface.CalculateRecommendLineSpacing() * pxscale;
            float descentInPx             = typeface.Descender * pxscale;
            float ascentInPx  = typeface.Ascender * pxscale;
            float lineGapInPx = typeface.LineGap * pxscale;

            PixelFarm.Drawing.Internal.RequestFontCacheAccess.SetActualFont(font, _system_id, typeface);
            PixelFarm.Drawing.Internal.RequestFontCacheAccess.SetGeneralFontMetricInfo(font,
                                                                                       pxSize,
                                                                                       ascentInPx,
                                                                                       descentInPx,
                                                                                       lineGapInPx,
                                                                                       recommedLineSpacingInPx);

            TextBufferSpan w           = new TextBufferSpan(new char[] { ' ' });
            Size           whiteSpaceW = MeasureString(ref w, font);

            PixelFarm.Drawing.Internal.RequestFontCacheAccess.SetWhitespaceWidth(font, _system_id, whiteSpaceW.Width);
            return(typeface);
        }
Beispiel #13
0
        public void FindCurrentHitWord(out int startAt, out int len)
        {
            if (_currentTextRun == null)
            {
                startAt = 0;
                len     = 0;
                return;
            }

            //
            //we read entire line
            //and send to line parser to parse a word
            StringBuilder stbuilder = new StringBuilder();

            _currentLine.CopyLineContent(stbuilder);
            string lineContent = stbuilder.ToString();
            //find char at

            TextBufferSpan textBufferSpan = new TextBufferSpan(lineContent.ToCharArray());

            using (ILineSegmentList segmentList = this.RootGfx.TextServices.BreakToLineSegments(ref textBufferSpan))
            {
                if (segmentList == null)
                {
                    startAt = 0;
                    len     = 0;
                    return;
                }

                int segcount = segmentList.Count;
                for (int i = 0; i < segcount; ++i)
                {
                    ILineSegment seg = segmentList[i];
                    if (seg.StartAt + seg.Length >= caret_char_index)
                    {
                        //stop at this segment
                        startAt = seg.StartAt;
                        len     = seg.Length;
                        return;
                    }
                }
            }

            //?
            startAt = 0;
            len     = 0;
        }
Beispiel #14
0
        public ILineSegmentList BreakToLineSegments(ref TextBufferSpan textBufferSpan)
        {
            //a text buffer span is separated into multiple line segment list
            char[] str         = textBufferSpan.GetRawCharBuffer();
            int    cur_startAt = textBufferSpan.start;


            MyLineSegmentList lineSegments = MyLineSegmentList.GetFreeLineSegmentList();

            foreach (BreakSpan breakSpan in _txtServices.BreakToLineSegments(str, textBufferSpan.start, textBufferSpan.len))
            {
                MyLineSegment lineSeg = new MyLineSegment(lineSegments, breakSpan.startAt, breakSpan.len);
                lineSeg.scriptLang = breakSpan.scLang;
                lineSegments.AddLineSegment(lineSeg);
            }
            return(lineSegments);
        }
Beispiel #15
0
        public ILineSegmentList BreakToLineSegments(ref TextBufferSpan textBufferSpan)
        {
            _resuableLineSegments.Clear();

            //a text buffer span is separated into multiple line segment list

            char[] str = textBufferSpan.GetRawCharBuffer();

            MyLineSegmentList lineSegs = new MyLineSegmentList(textBufferSpan.start, textBufferSpan.len);
            int cur_startAt            = textBufferSpan.start;

            foreach (BreakSpan breakSpan in _txtServices.BreakToLineSegments(str, textBufferSpan.start, textBufferSpan.len))
            {
                MyLineSegment lineSeg = new MyLineSegment(lineSegs, breakSpan.startAt, breakSpan.len);
                lineSeg.scriptLang = breakSpan.scLang;
                _resuableLineSegments.Add(lineSeg);
            }

            //TODO: review here,
            //check if we need to create new array everytime?
            lineSegs.SetResultLineSegments(_resuableLineSegments.ToArray());
            _resuableLineSegments.Clear();
            return(lineSegs);
        }
Beispiel #16
0
 public void MeasureString(ref TextBufferSpan textBufferSpan, RequestFont font, int maxWidth, out int charFit, out int charFitWidth)
 {
     WinGdiTextService.MeasureString(textBufferSpan.GetRawCharBuffer(), textBufferSpan.start, textBufferSpan.len, font, maxWidth, out charFit, out charFitWidth);
 }
Beispiel #17
0
 public void CalculateUserCharGlyphAdvancePos(ref TextBufferSpan textBufferSpan,
                                              RequestFont font, int[] outputGlyphAdvances, out int outputTotalW, out int outputLineHeight)
 {
     WinGdiTextService.CalculateGlyphAdvancePos(ref textBufferSpan, font, outputGlyphAdvances, out outputTotalW);
     outputLineHeight = WinGdiTextService.MeasureBlankLineHeight(font);
 }
Beispiel #18
0
 //
 public void CalculateUserCharGlyphAdvancePos(ref TextBufferSpan textBufferSpan, RequestFont font, int[] outputGlyphAdvances, out int outputTotalW, out int outputLineHeight)
 {
     CalculateUserCharGlyphAdvancePos(ref textBufferSpan, this.BreakToLineSegments(ref textBufferSpan), font, outputGlyphAdvances, out outputTotalW, out outputLineHeight);
 }
Beispiel #19
0
        public void CalculateUserCharGlyphAdvancePos(ref TextBufferSpan textBufferSpan,
                                                     ILineSegmentList lineSegs, RequestFont font,
                                                     int[] outputUserInputCharAdvance, out int outputTotalW, out int lineHeight)
        {
            //layout
            //from font
            //resolve for typeface
            //
            Typeface typeface = ResolveTypeface(font);

            _txtServices.SetCurrentFont(typeface, font.SizeInPoints);


            MyLineSegmentList mylineSegs = (MyLineSegmentList)lineSegs;
            float             scale      = typeface.CalculateScaleToPixelFromPointSize(font.SizeInPoints);

            outputTotalW = 0;
            int j   = mylineSegs.Count;
            int pos = 0; //start at 0

            _reusableTextBuffer.SetRawCharBuffer(textBufferSpan.GetRawCharBuffer());

            for (int i = 0; i < j; ++i)
            {
                //userGlyphPlanList.Clear();
                //userCharToGlyphMapList.Clear();
                //get each segment
                MyLineSegment lineSeg = mylineSegs.GetSegment(i);
                //each line seg may has different script lang
                _txtServices.CurrentScriptLang = lineSeg.scriptLang;
                //
                //CACHING ...., reduce number of GSUB/GPOS
                //
                //we cache used line segment for a while
                //we ask for caching context for a specific typeface and font size
                GlyphPlanSequence seq = _txtServices.GetUnscaledGlyphPlanSequence(_reusableTextBuffer,
                                                                                  lineSeg.StartAt,
                                                                                  lineSeg.Length);


                //IMPORTANT
                //num of glyph may more or less than original user input char buffer
                //


                //float g_x = 0;
                //float g_y = 0;
                //int baseY = (int)Math.Round(y);
                //int n = glyphPlanSeq.len;
                //int endBefore = glyphPlanSeq.startAt + n;

                ////***
                //_glsx.SetAssociatedTextureInfo(_glBmp);

                //List<float> vboBufferList = new List<float>();
                //List<ushort> indexList = new List<ushort>();

                //for (int i = glyphPlanSeq.startAt; i < endBefore; ++i)
                //{
                //    GlyphPlanList glyphPlanList = GlyphPlanSequence.UnsafeGetInteralGlyphPlanList(glyphPlanSeq);
                //    GlyphPlan glyph = glyphPlanList[i];

                //    Typography.Rendering.TextureGlyphMapData glyphData;
                //    if (!_fontAtlas.TryGetGlyphDataByCodePoint(glyph.glyphIndex, out glyphData))
                //    {
                //        //if no glyph data, we should render a missing glyph ***
                //        continue;
                //    }
                //    //if (scaleFromTexture != 1)
                //    //{

                //    //}
                //    //--------------------------------------
                //    //TODO: review precise height in float
                //    //--------------------------------------
                //    PixelFarm.Drawing.Rectangle srcRect = ConvToRect(glyphData.Rect);
                //    g_x = (float)(x + (glyph.ExactX * scale - glyphData.TextureXOffset) * scaleFromTexture); //ideal x
                //    g_y = (float)(y + (glyph.ExactY * scale - glyphData.TextureYOffset + srcRect.Height) * scaleFromTexture);


                //    //for sharp glyph
                //    //we adjust g_x,g_y to integer value
                //    //float g_y2 = (float)Math.Floor(g_y);

                //    g_x = (float)Math.Round(g_x);
                //    g_y = (float)Math.Floor(g_y);


                //    switch (textureKind)
                //    {
                //        case TextureKind.Msdf:

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

                //            break;
                //        case TextureKind.StencilGreyScale:

                //            //stencil gray scale with fill-color
                //            _glsx.DrawGlyphImageWithStecil(_glBmp,
                //             ref srcRect,
                //                g_x,
                //                g_y,
                //                scaleFromTexture);

                //            break;
                //        case TextureKind.Bitmap:
                //            _glsx.DrawSubImage(_glBmp,
                //             ref srcRect,
                //                g_x,
                //                g_y,
                //                scaleFromTexture);
                //            break;
                //        case TextureKind.StencilLcdEffect:
                //            _glsx.WriteVboToList(
                //              vboBufferList,
                //              indexList,
                //              ref srcRect,
                //              g_x,
                //              g_y,
                //              scaleFromTexture);
                //            break;
                //    }
                //}
                ////---------


                int seqLen = seq.Count;

                for (int s = 0; s < seqLen; ++s)
                {
                    UnscaledGlyphPlan glyphPlan = seq[s];

                    double actualAdvX = glyphPlan.AdvanceX;

                    outputTotalW +=
                        outputUserInputCharAdvance[pos + glyphPlan.input_cp_offset] +=
                            (int)Math.Round(actualAdvX * scale);
                }
                pos += lineSeg.Length;
            }

            //

            lineHeight = (int)Math.Round(typeface.CalculateRecommendLineSpacing() * scale);

            _reusableTextBuffer.SetRawCharBuffer(null);
        }
        public void PrepareStringForRenderVx(GLRenderVxFormattedString renderVxFormattedString, char[] buffer, int startAt, int len)
        {
            int top  = 0; //simulate top
            int left = 0; //simulate left

            _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;
            //--------------------------
            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

            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);
                float y_offset = acc_y + (float)Math.Round(glyph.OffsetY * px_scale - glyphData.TextureYOffset) + 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_x = (float)Math.Round(g_x); //***
                g_top = (float)Math.Floor(g_top);//adjust to integer num ***
                //
                _vboBuilder.WriteVboToList(ref srcRect, g_left, g_top);
            }
            //---
            //copy vbo result and store into  renderVx
            float[]  vertexList = _vboBuilder._buffer.ToArray();
            ushort[] indexList  = _vboBuilder._indexList.ToArray();
            //---

            renderVxFormattedString.IndexArrayCount = _vboBuilder._indexList.Count;
            renderVxFormattedString.IndexArray      = _vboBuilder._indexList.ToArray();
            renderVxFormattedString.VertexCoords    = _vboBuilder._buffer.ToArray();
            _vboBuilder.Clear();
        }
        public void PrepareStringForRenderVx(RenderVxFormattedString renderVx, char[] buffer, int startAt, int len)
        {
            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);

            float scale = _fontAtlas.TargetTextureScale;
            int   recommendLineSpacing = _fontAtlas.OriginalRecommendLineSpacing;

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

            y -= ((recommendLineSpacing) * scale);
            renderVx.RecommmendLineSpacing = (int)(recommendLineSpacing * scale);

            //
            float       scaleFromTexture = _finalTextureScale;
            TextureKind textureKind      = _fontAtlas.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);
            //--------------------------

            float g_x       = 0;
            float g_y       = 0;
            int   baseY     = (int)Math.Round(y);
            int   n         = glyphPlanSeq.len;
            int   endBefore = glyphPlanSeq.startAt + n;

            //***
            _glsx.SetAssociatedTextureInfo(_glBmp);
            //
            vboBufferList2.Clear();
            indexList2.Clear();

            float acc_x = 0;
            float acc_y = 0;

            for (int i = glyphPlanSeq.startAt; i < endBefore; ++i)
            {
                UnscaledGlyphPlanList glyphPlanList = GlyphPlanSequence.UnsafeGetInteralGlyphPlanList(glyphPlanSeq);
                UnscaledGlyphPlan     glyph         = glyphPlanList[i];

                Typography.Rendering.TextureFontGlyphData glyphData;
                if (!_fontAtlas.TryGetGlyphDataByGlyphIndex(glyph.glyphIndex, out glyphData))
                {
                    //if no glyph data, we should render a missing glyph ***
                    continue;
                }

                //--------------------------------------
                //TODO: review precise height in float
                //--------------------------------------
                PixelFarm.Drawing.Rectangle srcRect = ConvToRect(glyphData.Rect);

                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 + srcRect.Height) * scaleFromTexture);


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

                //g_x = (float)Math.Round(g_x);
                g_y = (float)Math.Floor(g_y);



                switch (textureKind)
                {
                case TextureKind.Msdf:

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

                    break;

                case TextureKind.StencilGreyScale:

                    //stencil gray scale with fill-color
                    _glsx.DrawGlyphImageWithStecil(_glBmp,
                                                   ref srcRect,
                                                   g_x,
                                                   g_y,
                                                   scaleFromTexture);

                    break;

                case TextureKind.Bitmap:
                    _glsx.DrawSubImage(_glBmp,
                                       ref srcRect,
                                       g_x,
                                       g_y,
                                       scaleFromTexture);
                    break;

                case TextureKind.StencilLcdEffect:
                    _glsx.WriteVboToList(
                        vboBufferList2,
                        indexList2,
                        ref srcRect,
                        g_x,
                        g_y,
                        scaleFromTexture);
                    break;
                }
            }
            //---------

            DrawingGL.GLRenderVxFormattedString renderVxFormattedString = (DrawingGL.GLRenderVxFormattedString)renderVx;
            renderVxFormattedString.IndexArray   = indexList2.ToArray();
            renderVxFormattedString.VertexCoords = vboBufferList2.ToArray();
            renderVxFormattedString.VertexCount  = indexList2.Count;
        }
        public void DrawString(char[] buffer, int startAt, int len, double x, double y)
        {
            _glsx.FontFillColor = painter.FontFillColor;

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

            float scale = _fontAtlas.TargetTextureScale;
            int   recommendLineSpacing = _fontAtlas.OriginalRecommendLineSpacing;

            //--------------------------
            //TODO:
            //if (x,y) is left top
            //we need to adjust y again
            y -= ((_fontAtlas.OriginalRecommendLineSpacing) * scale);

            EnsureLoadGLBmp();
            //
            float       scaleFromTexture = _finalTextureScale;
            TextureKind textureKind      = _fontAtlas.TextureKind;

            float g_x       = 0;
            float g_y       = 0;
            int   baseY     = (int)Math.Round(y);
            int   n         = glyphPlanSeq.len;
            int   endBefore = glyphPlanSeq.startAt + n;

            //-------------------------------------
            _glsx.LoadTexture1(_glBmp);
            //-------------------------------------

            _vboBufferList.Clear(); //clear before use
            _indexList.Clear();     //clear before use


            float acc_x = 0;
            float acc_y = 0;

            for (int i = glyphPlanSeq.startAt; i < endBefore; ++i)
            {
                UnscaledGlyphPlanList glyphPlanList = GlyphPlanSequence.UnsafeGetInteralGlyphPlanList(glyphPlanSeq);
                UnscaledGlyphPlan     glyph         = glyphPlanList[i];

                Typography.Rendering.TextureFontGlyphData glyphData;
                if (!_fontAtlas.TryGetGlyphDataByGlyphIndex(glyph.glyphIndex, out glyphData))
                {
                    //if no glyph data, we should render a missing glyph ***
                    continue;
                }
                //--------------------------------------
                //TODO: review precise height in float
                //--------------------------------------
                PixelFarm.Drawing.Rectangle srcRect = ConvToRect(glyphData.Rect);


                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 + srcRect.Height) * scaleFromTexture);


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

                //g_x = (float)Math.Round(g_x);
                g_y = (float)Math.Floor(g_y);


                switch (textureKind)
                {
                case TextureKind.Msdf:

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

                    break;

                case TextureKind.StencilGreyScale:

                    //stencil gray scale with fill-color
                    _glsx.DrawGlyphImageWithStecil(_glBmp,
                                                   ref srcRect,
                                                   g_x,
                                                   g_y,
                                                   scaleFromTexture);

                    break;

                case TextureKind.Bitmap:
                    _glsx.DrawSubImage(_glBmp,
                                       ref srcRect,
                                       g_x,
                                       g_y,
                                       scaleFromTexture);
                    break;

                case TextureKind.StencilLcdEffect:

                    _glsx.WriteVboToList(
                        _vboBufferList,
                        _indexList,
                        ref srcRect,
                        g_x,
                        g_y,
                        scaleFromTexture);

                    break;
                }
            }
            //-------
            //we create vbo first
            //then render
            _glsx.DrawGlyphImageWithSubPixelRenderingTechnique3(_vboBufferList.ToArray(), _indexList.ToArray());
        }
Beispiel #23
0
 public ILineSegmentList BreakToLineSegments(ref TextBufferSpan textBufferSpan)
 {
     throw new NotImplementedException();
 }
Beispiel #24
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
        }
Beispiel #25
0
        public void DrawString(Painter p, char[] buffer, int startAt, int len, double x, double y)
        {
            AggPainter painter = p as AggPainter;



            if (painter == null)
            {
                return;
            }
            //

            int width  = painter.Width;
            int height = painter.Height;

            if (!_pixelBlenderSetup)
            {
                SetupMaskPixelBlender(width, height);
                _pixelBlenderSetup = true;
            }

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

            float scale = 1;// _fontAtlas.TargetTextureScale;
            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 gx    = 0;
            float gy    = 0;
            int   baseY = (int)Math.Round(y);

            float acc_x = 0;
            float acc_y = 0;

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

            //painter.DestBitmapBlender.OutputPixelBlender = maskPixelBlenderPerCompo; //change to new blender
            painter.DestBitmapBlender.OutputPixelBlender = _maskPixelBlenderPerCompo; //change to new blender

            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)(x + (ngx - glyphData.TextureXOffset) * scaleFromTexture); //ideal x
                gy = (float)(y + (ngy - glyphData.TextureYOffset - srcH + lineHeight) * scaleFromTexture);

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

                //clear with solid black color
                //_maskBufferPainter.Clear(Color.Black);
                _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), srcW, srcH);

                //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);
            }
        }
Beispiel #26
0
 public PixelFarm.Drawing.Size MeasureString(ref TextBufferSpan textBufferSpan, RequestFont font)
 {
     return(WinGdiTextService.MeasureString(textBufferSpan.GetRawCharBuffer(), textBufferSpan.start, textBufferSpan.len, font));
 }
Beispiel #27
0
        //==============================================

        public static void CalculateGlyphAdvancePos(ref TextBufferSpan textBufferSpan,
                                                    RequestFont font, int[] outputGlyphAdvances, out int outputTotalW)
        {
            unsafe
            {
                outputTotalW = 0;
                int len = textBufferSpan.len;
                if (len == 0)
                {
                    return;
                }

                WinGdiFont winfont = SetFont(font);
                //ushort* glyhIndics = stackalloc ushort[len];
                //fixed (char* s = &str[startAt])
                //{
                //    NativeTextWin32.GetGlyphIndices(
                //        win32MemDc.DC,
                //        s,
                //        len,
                //        glyhIndics,
                //        0);
                //}


                byte[] encoding = s_en.GetBytes(
                    textBufferSpan.GetRawCharBuffer(),
                    textBufferSpan.start,
                    len);
                NativeTextWin32.FontABC[] abcWidths = winfont.GetInteralABCArray();
                int totalW = 0;
                for (int i = 0; i < len; ++i)
                {
                    //ushort glyphIndex = *(glyhIndics + i);
                    int enc_index = encoding[i];
                    if (enc_index == 0)
                    {
                        break;//?
                    }
                    totalW += outputGlyphAdvances[i] = abcWidths[enc_index].Sum;
                }
            }
            //unsafe
            //{
            //    SetFont(font);
            //    NativeTextWin32.GCP_RESULTS gpcResult = new NativeTextWin32.GCP_RESULTS();
            //    int[] caretpos = new int[len];
            //    uint[] lpOrder = new uint[len];
            //    int[] lpDx = new int[len];
            //    fixed (int* lpdx_h = &lpDx[0])
            //    fixed (uint* lpOrder_h = &lpOrder[0])
            //    fixed (int* caretpos_h = &caretpos[0])
            //    fixed (char* str_h = &str[startAt])
            //    {
            //        gpcResult.lpCaretPos = caretpos_h;
            //        gpcResult.lpOrder = lpOrder_h;
            //        gpcResult.lpDx = lpdx_h;
            //        //gpcResult.
            //        ////gpcResult.lpCaretPos =
            //        NativeTextWin32.GetCharacterPlacement(
            //            win32MemDc.DC,
            //            str_h,
            //            len,
            //            len, ref gpcResult, 0);

            //    }

            //}
        }
Beispiel #28
0
        public void CalculateUserCharGlyphAdvancePos(ref TextBufferSpan textBufferSpan,
                                                     ILineSegmentList lineSegs, RequestFont font,
                                                     int[] outputUserInputCharAdvance, out int outputTotalW, out int lineHeight)
        {
            //layout
            //from font
            //resolve for typeface
            //
            Typeface typeface = ResolveTypeface(font);

            _typographyTxtServices.SetCurrentFont(typeface, font.SizeInPoints);


            MyLineSegmentList mylineSegs = (MyLineSegmentList)lineSegs;
            float             scale      = typeface.CalculateScaleToPixelFromPointSize(font.SizeInPoints);

            outputTotalW = 0;
            int j   = mylineSegs.Count;
            int pos = 0; //start at 0

            _reusableTextBuffer.SetRawCharBuffer(textBufferSpan.GetRawCharBuffer());

            for (int i = 0; i < j; ++i)
            {
                //userGlyphPlanList.Clear();
                //userCharToGlyphMapList.Clear();
                //get each segment
                MyLineSegment lineSeg = mylineSegs.GetSegment(i);
                //each line seg may has different script lang
                _typographyTxtServices.CurrentScriptLang = lineSeg.scriptLang;
                //
                //CACHING ...., reduce number of GSUB/GPOS
                //
                //we cache used line segment for a while
                //we ask for caching context for a specific typeface and font size
                GlyphPlanSequence seq = _typographyTxtServices.GetUnscaledGlyphPlanSequence(_reusableTextBuffer,
                                                                                            lineSeg.StartAt,
                                                                                            lineSeg.Length);

                GlyphPlanList planList = GlyphPlanSequence.UnsafeGetInteralGlyphPlanList(seq);
                //IMPORTANT
                //num of glyph may more or less than original user input char buffer
                //


                int endAt       = seq.startAt + seq.len;
                int seq_startAt = seq.startAt;

                for (int s = seq_startAt; s < endAt; ++s)
                {
                    GlyphPlan glyphPlan  = planList[s];
                    float     tx         = glyphPlan.ExactX;
                    float     ty         = glyphPlan.ExactY;
                    double    actualAdvX = glyphPlan.AdvanceX;

                    outputTotalW +=
                        outputUserInputCharAdvance[pos + glyphPlan.input_cp_offset] +=
                            (int)Math.Round(actualAdvX * scale);
                }
                pos += lineSeg.Length;
            }

            //

            lineHeight = (int)Math.Round(typeface.CalculateRecommendLineSpacing() * scale);

            _reusableTextBuffer.SetRawCharBuffer(null);
        }
        internal Size MeasureStringSize(char[] buffer, int startIndex, int len, RequestFont f)
        {
            TextBufferSpan textSpan = new TextBufferSpan(buffer, startIndex, len);

            return(this.SampleIFonts.MeasureString(ref textSpan, f));
        }
        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);

            //
            _pcx.FontFillColor = _painter.FontFillColor;
            _pcx.LoadTexture(_glBmp);


            //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 = 1;
            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



            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);
                float y_offset = acc_y + (float)Math.Round(glyph.OffsetY * px_scale - glyphData.TextureYOffset) + 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_x = (float)Math.Round(g_x); //***
                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
                }
#endif
                if (textureKind == TextureKind.Msdf)
                {
                    _pcx.DrawSubImageWithMsdf(_glBmp,
                                              ref srcRect,
                                              g_left,
                                              g_top,
                                              scaleFromTexture);
                }
                else
                {
                    switch (DrawingTechnique)
                    {
                    case GlyphTexturePrinterDrawingTechnique.Stencil:
                        if (UseVBO)
                        {
                            _vboBuilder.WriteVboToList(
                                ref srcRect,
                                g_left, g_top);
                        }
                        else
                        {
                            //stencil gray scale with fill-color
                            _pcx.DrawGlyphImageWithStecil(_glBmp,
                                                          ref srcRect,
                                                          g_left,
                                                          g_top,
                                                          scaleFromTexture);
                        }
                        break;

                    case GlyphTexturePrinterDrawingTechnique.Copy:
                        if (UseVBO)
                        {
                            _vboBuilder.WriteVboToList(
                                ref srcRect,
                                g_left, g_top);
                        }
                        else
                        {
                            _pcx.DrawSubImage(_glBmp,
                                              ref srcRect,
                                              g_left,
                                              g_top,
                                              1);
                        }
                        break;

                    case GlyphTexturePrinterDrawingTechnique.LcdSubPixelRendering:
                        if (UseVBO)
                        {
                            _vboBuilder.WriteVboToList(
                                ref srcRect,
                                g_left, g_top);
                        }
                        else
                        {
                            _pcx.DrawGlyphImageWithSubPixelRenderingTechnique2_GlyphByGlyph(
                                ref srcRect,
                                g_left,
                                g_top,
                                1);
                        }
                        break;
                    }
                }
            }
            //-------------------------------------------
            //
            if (UseVBO)
            {
                switch (DrawingTechnique)
                {
                case GlyphTexturePrinterDrawingTechnique.Copy:
                    _pcx.DrawGlyphImageWithCopy_VBO(_vboBuilder);
                    break;

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

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

                _vboBuilder.Clear();
            }
        }