public override void CopyOutputPixelBuffer(int x, int y, int w, int h, IntPtr outputBuffer)
        {
            //1. This version support on Win32 only
            //2. this is an example, to draw directly into the memDC, not need to create control
            //3. x and y set to 0
            //4. w and h must be the width and height of the viewport


            unsafe
            {
                //create new memdc
                Win32.NativeWin32MemoryDc memDc = new Win32.NativeWin32MemoryDc(w, h);
                memDc.PatBlt(Win32.NativeWin32MemoryDc.PatBltColor.White);
                //TODO: check if we need to set init font/brush/pen for the new DC or not
                gdiPlusViewport.FullMode = true;
                //pain to the destination dc
                this.gdiPlusViewport.PaintMe(memDc.DC);
                IntPtr outputBits = memDc.PPVBits;
                //Win32.MyWin32.memcpy((byte*)outputBuffer, (byte*)memDc.PPVBits, w * 4 * h);
                memDc.CopyPixelBitsToOutput((byte *)outputBuffer);
                memDc.Dispose();
            }
        }
        public void DrawString(char[] textBuffer, int startAt, int len, double x, double y)
        {
            //TODO: review performance
            memdc.PatBlt(Win32.NativeWin32MemoryDc.PatBltColor.White, 0, 0, bmpWidth, bmpHeight);
            memdc.TextOut(textBuffer);
            //memdc.BitBltTo(destHdc);
            // Win32.Win32Utils.BitBlt(hdc, 0, 0, bmpWidth, 50, memHdc, 0, 0, Win32.MyWin32.SRCCOPY);
            //---------------
            int stride = 4 * ((bmpWidth * 32 + 31) / 32);

            //Bitmap newBmp = new Bitmap(bmpWidth, 50, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            //var bmpData = newBmp.LockBits(new Rectangle(0, 0, bmpWidth, 50), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            byte[] tmp1 = new byte[stride * 50];
            System.Runtime.InteropServices.Marshal.Copy(memdc.PPVBits, tmp1, 0, tmp1.Length);
            //---------------
            int pos = 3;

            for (int r = 0; r < 50; ++r)
            {
                for (int c = 0; c < stride; ++c)
                {
                    tmp1[pos] = 255;
                    pos      += 4;
                    c        += 4;
                }
            }


            memdc.MeasureTextSize(textBuffer, out bmpWidth, out bmpHeight);
            var actualImg = new Agg.ActualImage(bmpWidth, bmpHeight);

            //------------------------------------------------------
            //copy bmp from specific bmp area
            //and convert to GLBmp
            Agg.TempMemPtr buffer = PixelFarm.Agg.ActualImage.GetBufferPtr(actualImg);
            unsafe
            {
                byte *header = (byte *)memdc.PPVBits;
                byte *dest0  = (byte *)buffer.Ptr;
                {
                    byte *dest    = dest0;
                    byte *rowHead = header;
                    int   rowLen  = bmpWidth * 4;
                    for (int h = 0; h < bmpHeight; ++h)
                    {
                        header = rowHead;
                        for (int n = 0; n < rowLen;)
                        {
                            //move next
                            *(dest + 0) = *(header + 0);
                            *(dest + 1) = *(header + 1);
                            *(dest + 2) = *(header + 2);
                            //*(dest + 3) = *(header + 3);
                            *(dest + 3) = 255;
                            header     += 4;
                            dest       += 4;
                            n          += 4;
                        }
                        //finish one row
                        rowHead += stride;
                    }
                }
            }
            buffer.Release();

            //------------------------------------------------------
            GLBitmap glBmp = new GLBitmap(actualImg);

            _glsx.DrawImage(glBmp, (float)x, (float)y);
            glBmp.Dispose();
        }