public void SetGlyph(int x, int y, char value)
        {
            if (Glyphs[y] == null)
            {
                Glyphs[y] = new RenderGlyph[ConsoleSize.Width];
            }

            Glyphs[y][x] = new RenderGlyph(value);
        }
        public void SetGlyph(int x, int y, RenderGlyph glyph)
        {
            if (Glyphs[y] == null)
            {
                Glyphs[y] = new RenderGlyph[ConsoleSize.Width];
            }

            Glyphs[y][x] = glyph;
        }
        public void Write(string text)
        {
            for (int i = 0; i < text.Length; i++)
            {
                if (Cursor.X >= ConsoleSize.Width)
                {
                    Cursor = new Point(0, Cursor.Y + 1);
                }
                if (Cursor.Y >= ConsoleSize.Height)
                {
                    Cursor = new Point(Cursor.X, ConsoleSize.Height - 1);
                }

                RenderGlyph glyph = new RenderGlyph(text[i]);

                if (InheritDefaultColors)
                {
                    glyph.Background = BackColor;
                    glyph.Foreground = ForeColor;
                }

                SetGlyph(Cursor.X, Cursor.Y, glyph);

                if (Cursor.X + 1 < ConsoleSize.Width)
                {
                    Cursor = new Point(Cursor.X + 1, Cursor.Y);
                }
                else
                {
                    Cursor = new Point(0, Cursor.Y + 1);
                }

                if (Cursor.Y >= ConsoleSize.Height)
                {
                    Cursor = new Point(Cursor.X, ConsoleSize.Height - 1);
                    Glyphs.Rotate(1);
                    if (Glyphs[Cursor.Y] != null)
                    {
                        for (int w = 0; w < Glyphs[Cursor.Y].Length; w++)
                        {
                            Glyphs[Cursor.Y][w] = null;
                        }
                    }
                }
            }
        }
        protected override void Renderer_Draw(RenderThread sender, FrameStageEventArgs args)
        {
            if (!sender.IsMainThread() && !sender.Asynchronous)
            {
                throw new InvalidOperationException("Draw operation initiated from secondary thread when supposed to run in Sync mode.");
            }

            float cellX = sender.InternalResolution.Width / (float)ConsoleSize.Width;
            float cellY = sender.InternalResolution.Height / (float)ConsoleSize.Height;

            List <float> vertices = new List <float>(4096);
            List <uint>  indices  = new List <uint>(4096);

            float[] db = ColorToFloatArray(DefaultBackColor);
            float[] df = ColorToFloatArray(DefaultForeColor);

            int vertexCount = 0;

            for (int xi = 0; xi < ConsoleSize.Width; xi++)
            {
                float x = xi * cellX;
                for (int yi = 0; yi < ConsoleSize.Height; yi++)
                {
                    RenderGlyph glyphData = GetGlyph(xi, yi);

                    if (ShowCursor && xi == Cursor.X && yi == Cursor.Y && glyphData == null)
                    {
                        int val = (int)((args.CurrentTime.TotalRuntime / 1000.0f) / BlinkInterval);
                        if (val % 2 == 0 || BlinkInterval == 0)
                        {
                            glyphData = new RenderGlyph('_');
                        }
                    }

                    float     y       = yi * cellY;
                    Rectangle texRec  = Rectangle.Empty;
                    int       glyphId = (int)(glyphData?.Glyph ?? ' ');
                    if (fontAtlas.ContainsId(glyphId))
                    {
                        texRec = fontAtlas.GetPointerById(glyphId).Bounds;
                    }
                    else if (fontAtlas.ContainsId(0x558))
                    {
                        texRec = fontAtlas.GetPointerById(0x558).Bounds;
                    }
                    else
                    {
                        texRec = fontAtlas.GetPointerById((int)'?').Bounds;
                    }

                    float[] b = glyphData == null || !glyphData.Background.HasValue ? db : ColorToFloatArray(glyphData.Background.Value);
                    float[] f = glyphData == null || !glyphData.Foreground.HasValue ? df : ColorToFloatArray(glyphData.Foreground.Value);

                    int qi = vertexCount;

                    vertices.AddRange(new float[] {  // Add vertices
                        x, y,                        // 0,0 (A)
                        texRec.X, texRec.Y,          // Texture X,Y
                        b[0], b[1], b[2], b[3],      // Back
                        f[0], f[1], f[2], f[3],      // Fore

                        x + cellX, y,                // 1,0 (B)
                        texRec.Right, texRec.Y,      // Texture X,Y
                        b[0], b[1], b[2], b[3],      // Back
                        f[0], f[1], f[2], f[3],      // Fore

                        x + cellX, y + cellY,        // 1,1 (C)
                        texRec.Right, texRec.Bottom, // Texture X,Y
                        b[0], b[1], b[2], b[3],      // Back
                        f[0], f[1], f[2], f[3],      // Fore

                        x, y + cellY,                //0,1 (D)
                        texRec.X, texRec.Bottom,     // Texture X,Y
                        b[0], b[1], b[2], b[3],      // Back
                        f[0], f[1], f[2], f[3],      // Fore
                    });

                    indices.AddRange(new uint[]
                    {
                        (uint)(qi + 1), // B
                        (uint)(qi + 3), // D
                        (uint)(qi),     // A
                        (uint)(qi + 1), // B
                        (uint)(qi + 2), // C
                        (uint)(qi + 3), // D
                    });

                    vertexCount += 4;
                }
            }

            Gl.BindVertexArray(VAO);
            Gl.BindBuffer(BufferTarget.ArrayBuffer, VBO);

            float[] fvertices = vertices.ToArray();
            vertices.Clear();

            uint[] iindices = indices.ToArray();
            indices.Clear();

            CheckGlErrors("pre-vab");
            GCHandle buffAddress = GCHandle.Alloc(fvertices, GCHandleType.Pinned);

            Gl.BufferData(BufferTarget.ArrayBuffer, fvertices.Length * sizeof(float), buffAddress.AddrOfPinnedObject(), BufferUsageHint.StreamDraw);
            buffAddress.Free();

            CheckGlErrors("pre-eab");
            buffAddress = GCHandle.Alloc(iindices, GCHandleType.Pinned);
            Gl.BufferData(BufferTarget.ElementArrayBuffer, iindices.Length * sizeof(float), buffAddress.AddrOfPinnedObject(), BufferUsageHint.StreamDraw);
            buffAddress.Free();

            CheckGlErrors("predraw");
            Gl.DrawElements(BeginMode.Triangles, iindices.Length, DrawElementsType.UnsignedInt, 0);

            CheckGlErrors("final");
            Gl.BindVertexArray(0);
            CheckGlErrors("unbind");
        }