using System.Diagnostics;
using System.Text;
using GraphicsManager.Enums;
using GraphicsManager.Interfaces;
using GraphicsManager.Objects;
using GraphicsManager.Objects.Core;
using GraphicsManager.Structs;
using Luski.Enums;
using Luski.net.Structures.Public;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common.Input;

namespace Luski.GUI.MainScreen.UI.LuskiControls;

public class LuskiLabel : LabelBase
{
    public LuskiLabel() : this(Globals.DefaultFont) { }
    public LuskiLabel(FontInteraction fi) : base(fi) { }
    public Color4 DefaultColor { get; set; } = Color4.White;
    
    public override void LoadToParent(IParent window, IWindow win)
    {
	    if (Loaded) return;
	    if (Shader is null) Shader = Globals.GradientShader[win.Context];
	    base.LoadToParent(window, win);
    }
    float _alpha = 1;
    protected virtual (Color4,Color4) getGradcols(int Start, int charter, int End, int StartLine, int Line, int EndLine, GradType GT, Color4[] Colors)
    {
	    Vector2i cl = GetCharLocation(charter);
	    Vector2i cs = GetSizeOfChar(charter);
	    Vector2i cls = GetCharLocation(Start);
	    Vector2i cle = GetCharLocation(End);
	    Vector2i cse = GetSizeOfChar(End);
	    if (GT == GradType.Line && StartLine != EndLine)
	    {
		    for (int i = StartLine; i < EndLine; i++)
		    {
			    Vector2i dis = new(MaxLineSizes[i].Item1.X, 0);
			    if (i == StartLine) dis -= new Vector2i(cls.X, 0);
			    cle += dis;
			    if (i < Line) cl += dis;
		    }
	    }
	    else if (GT == GradType.Block && StartLine != EndLine)
	    {
		    cls = new(0, cl.Y);
		    int longest = MaxLineSizes[StartLine].Item1.X;
		    for (int i = StartLine+1; i <= EndLine; i++)
		    {
			    if (MaxLineSizes[i].Item1.X > longest) longest = MaxLineSizes[i].Item1.X;
		    }

		    cse = new(0);
		    cle = new(longest, cle.X);
	    }
	    
	    return new(getGradcol(cls.X, cl.X, cle.X + cse.X, Colors), getGradcol(cls.X, cl.X + cs.X, cle.X + cse.X, Colors));
    }
    protected virtual Color4 getGradcol(int Start, int pos, int End, Color4[] Colors)
    {
	    pos -= Start;
	    End -= Start;
	    float travel =  (float)End/(Colors.Length - 1);
	    int i = 1;
	    while (travel * i < pos)
	    {
		    i++;
	    }
	    i--;
	    float t = Math.Clamp((pos-(travel*i))/travel, 0, 1);
	    Color4 LeftColor, RightColor;
	    try
	    {
		    LeftColor = Colors[i];
		    RightColor = Colors[i + 1];
	    }
	    catch (Exception e)
	    {
		    LeftColor = Color4.DarkRed;
		    RightColor = Color4.DarkRed;
	    }
	    

	    float r = LeftColor.R + (RightColor.R - LeftColor.R) * t;
	    float g = LeftColor.G + (RightColor.G - LeftColor.G) * t;
	    float b = LeftColor.B + (RightColor.B - LeftColor.B) * t;
	    float a = LeftColor.A + (RightColor.A - LeftColor.A) * t;

	    return new Color4(r, g, b, a * _alpha);
    }
    
    List<Tuple<TextCode, int, int, object?>> Commands = new();

    public string PlainText { get; protected set; } = string.Empty;
    private List<(Vector2i, FontInteraction)> MaxLineSizes = new(); 

    public override string Text
    {
	    get => base.Text;
	    set
	    {
		    if (value is null) value = string.Empty;
		    text = value;
		    text_Calculated = string.Empty;
		    PlainText = string.Empty;
		    MaxLineSizes.Clear();
		    float max_x = 0, lines = 1, char_x = 0F;
		    int len = Text.Length;
		    bool use_slash = true, usebrac = true;
		    List<int> Rainbow_End = new();
		    List<int> Gradient_End = new();
		    List<int> Color_End = new(); 
		    List<int> Font_Starts = new(); 
		    List<int> Link_Starts = new(); 
		    Commands.Clear();
		    List<(GradType, int)> RainGrad = new();
		    List<(Color4[], GradType, int)> Grad = new();
		    List<(Color4, BlendType)> ccccc = new();
		    List<bool> Itilacs = new();
		    List<FontSize> Fonts = new();
		    List<uint> Sizes = new();
		    List<string> Links = new();
		    FontInteraction Current = Font;
		    FontInteraction? Largest = null;
		    int LastFontEnd = 0;
		    StringBuilder sb = new();
		    uint lh = 0;
		    float lw = 0;
		    uint max_lh = 0;
		    
		    for (int i = 0; i < len; i++)
		    {
			    char c;
			    if (PasswordChar is null)
				    c = Text[i];
			    else
				    c = PasswordChar.Value;
			    bool n = (c == '\n');

			    if (Text[i] == '\\' && use_slash)
			    {
				    if (i + 1 < len)
				    {
					    char tm = Text[i + 1];
					    if (tm == '\\')
					    {
						    use_slash = false;
						    continue;
					    }
					    if (tm == '[')
					    {
						    usebrac = false;
						    continue;
					    }
				    }

				    
			    }

			    try
			    {
					if (usebrac && Text[i] == '[')
				    {
					    int brack = Text.IndexOf(']', i);
					    string com = Text[(i + 1)..(brack )].Replace("\" ", "\"");
					    while (com.Contains("  "))
					    {
						    com = com.Replace("  ", " ");
					    }
					    string[] args = com.Split('=', '"', ' ');
					    
					    FontInteraction tmp;
					    if (args[0][0] != '/')
					    {
						    switch (args[0])
						    {
							    case "rainbow":
								    Rainbow_End.Add(sb.Length);
								    GradType rgt = GradType.Line;
								    for (int j = 1; j < args.Length-2; j+=3)
								    {
									    switch (args[j])
									    {
										    case "type":
											    rgt = (GradType)byte.Parse(args[j + 2]);
											    break;
									    }
								    }
								    RainGrad.Add(new(rgt, (int)lines-1));
								    i = brack;
								    continue;
							    case "gradient":
								    List<Color> cols = new();
								    Gradient_End.Add(sb.Length);
								    GradType gt = GradType.Line;
								    for (int j = 1; j < args.Length-2; j+=3)
								    {
									    switch (args[j])
									    {
										    case "colors":
											    for (int w = 0; w < args[j+2].Length - 7; w+=8)
											    {
												    cols.Add(new(args[j+2][w..(w+8)]));
											    }
											    break;
										    case "type":
											    gt = (GradType)byte.Parse(args[j + 2]);
											    break;
									    }
								    }
								    Grad.Add(new(cols.ToArray().ToColor4Array(), gt, (int)lines-1));
								    i = brack;
								    continue;
							    case "color":
								    i = brack;
								    Color_End.Add(sb.Length);
								    Color col = new(args[2].Replace("#", ""));
								    BlendType bt = BlendType.None;
								    for (int j = 3; j < args.Length-2; j+=3)
								    {
									    switch (args[j])
									    {
										    case "blend":
											    bt = (BlendType)byte.Parse(args[j + 2]);
											    break;
									    }
								    }
								    ccccc.Add(new(col.ToColor4(), bt));
								    i = brack;
								    continue;
							    case "fontsize":
								    FontSize fs = (FontSize)int.Parse(args[2]); 
								    tmp = Current.Clone();
								    tmp.FontSize = fs;
								    if (Fonts.Count != 0 || Itilacs.Count != 0 || Sizes.Count != 0)
								    {
									    int pos = Font_Starts.Count - 1;
									    int last_Start = Font_Starts[pos];
									    int end = sb.Length - 1;
									    if (end != -1 && last_Start != end)
										    Commands.Add(new(TextCode.Font, last_Start, end, Current));
									    Font_Starts.RemoveAt(pos);
								    }
								    Fonts.Add(fs);
								    Font_Starts.Add(sb.Length);
								    Current = tmp;
								    i = brack;
								    continue;
							    case "px":
								    uint ph = uint.Parse(args[2]);
								    tmp = Current.Clone();
								    tmp.PixelHeight = ph;
								    if (Fonts.Count != 0 || Itilacs.Count != 0 || Sizes.Count != 0)
								    {
									    int pos = Font_Starts.Count - 1;
									    int last_Start = Font_Starts[pos];
									    int end = sb.Length - 1;
									    if (end != -1 && last_Start != end)
										    Commands.Add(new(TextCode.Font, last_Start, end, Current));
									    Font_Starts.RemoveAt(pos);
								    }
								    i = brack;
								    Sizes.Add(ph);
								    Font_Starts.Add(sb.Length);
								    Current = tmp;
								    i = brack;
								    continue;
							    case "url":
								    Link_Starts.Add(i);
								    Links.Add(args[2]);
								    i = brack;
								    continue;
							    case "i":
								    tmp = Current.Clone();
								    tmp.Italic = true;
								    if (Fonts.Count != 0 || Itilacs.Count != 0 || Sizes.Count != 0)
								    {
									    int pos = Font_Starts.Count - 1;
									    int last_Start = Font_Starts[pos];
									    int end = sb.Length - 1;
									    if (end != -1 && last_Start != end)
										    Commands.Add(new(TextCode.Font, last_Start, end, Current));
									    Font_Starts.RemoveAt(pos);
								    }
								    Itilacs.Add(true);
								    Font_Starts.Add(sb.Length);
								    Current = tmp;
								    i = brack;
								    continue;
							    
						    }
					    }
					    else
					    {
						    if (com == "/rainbow")
						    {
							    if (Rainbow_End.Count == 0)
							    {
								    i = brack;
								    continue;
							    }
							    (GradType, int) cc = RainGrad[RainGrad.Count - 1];
							    Commands.Add(new(TextCode.Rainbow, Rainbow_End[Rainbow_End.Count-1], sb.Length-1, new Tuple<GradType, int, int>(cc.Item1, cc.Item2, (int)lines-1)));
							    Rainbow_End.RemoveAt(Rainbow_End.Count-1);
							    i = brack;
							    continue;
						    }
						    if (com == "/gradient")
						    {
							    if (Gradient_End.Count == 0)
							    {
								    i = brack;
								    continue;
							    }
							    var cc = Grad[Grad.Count - 1];
							    Commands.Add(new(TextCode.Gradient, Gradient_End[Gradient_End.Count-1], sb.Length-1, new Tuple<Color4[], GradType, int, int>(cc.Item1, cc.Item2, cc.Item3, (int)lines-1)));
							    Gradient_End.RemoveAt(Gradient_End.Count-1);
							    Grad.RemoveAt(Grad.Count-1);
							    i = brack;
							    continue;
						    }
						    if (com == "/color")
						    {
							    if (ccccc.Count == 0)
							    {
								    i = brack;
								    continue;
							    }
							    Commands.Add(new(TextCode.Color, Color_End[Color_End.Count-1], sb.Length-1, new Tuple<Color4, BlendType>(ccccc[ccccc.Count-1].Item1, ccccc[ccccc.Count-1].Item2) ));
							    Color_End.RemoveAt(Color_End.Count-1);
							    ccccc.RemoveAt(ccccc.Count-1);
							    i = brack;
							    continue;
						    }
						    if (com == "/url")
						    {
							    Commands.Add(new(TextCode.url, Link_Starts[Link_Starts.Count-1], sb.Length-1, Links[Links.Count-1]));
							    Link_Starts.RemoveAt(Link_Starts.Count-1);
							    Links.RemoveAt(Links.Count-1);
							    i = brack;
							    continue;
						    }

						    if (com == "/fontsize" || com == "/i" || com == "/px")
						    {
							    int pos = Font_Starts.Count - 1;
							    if (pos == -1)
							    {
								    i = brack;
								    continue;
							    }
							    if (pos >= 0)
							    {
								    int last_Start = Font_Starts[pos];
								    Font_Starts.RemoveAt(pos);
								    if (LastFontEnd != sb.Length - 1)
								    {
									    LastFontEnd = sb.Length - 1;
									    Commands.Add(new(TextCode.Font, last_Start, LastFontEnd, Current));
								    }
							    }
						    }
						    
						    
						    if (com == "/fontsize")
						    {
							    Fonts.RemoveAt(Fonts.Count - 1);
							    if (Fonts.Count != 0)
							    {
								    Current = Current.Clone();
								    Current.FontSize = Fonts[Fonts.Count - 1];
								    Font_Starts.Add(sb.Length-1);
							    }
							    else
							    {
								    if (Sizes.Count == 0 && Itilacs.Count == 0)
										Current = Font;
								    else
								    {
									    Current = Current.Clone();
									    Current.FontSize = Font.FontSize;
									    Font_Starts.Add(sb.Length-1);
								    }
							    }
							    i = brack;
							    continue;
						    }
						    if (com == "/i")
						    {
							    Itilacs.RemoveAt(Itilacs.Count - 1);
							    if (Itilacs.Count != 0)
							    {
								    Current = Current.Clone();
								    Current.Italic = Itilacs[Itilacs.Count - 1];
								    Font_Starts.Add(sb.Length-1);
							    }
							    else
							    {
								    if (Sizes.Count == 0 && Fonts.Count == 0)
									    Current = Font;
								    else
								    {
									    Current = Current.Clone();
									    Current.Italic = Font.Italic;
									    Font_Starts.Add(sb.Length-1);
								    }
							    }
							    i = brack;
							    continue;
						    }
						    if (com == "/px")
						    {
							    if (Sizes.Count == 0)
							    {
								    i = brack;
								    continue;
							    }
							    Sizes.RemoveAt(Sizes.Count - 1);
							    if (Sizes.Count != 0)
							    {
								    Current = Current.Clone();
								    Current.PixelHeight = Sizes[Sizes.Count - 1];
								    Font_Starts.Add(sb.Length-1);
							    }
							    else
							    {
								    if (Itilacs.Count == 0 && Fonts.Count == 0)
									    Current = Font;
								    else
								    {
									    Current = Current.Clone();
									    Current.PixelHeight = Font.PixelHeight;
									    Font_Starts.Add(sb.Length-1);
								    }
							    }
							    i = brack;
							    continue;
						    }
					    }
				    }
			    }
			    catch (Exception e)
			    {
				    Console.WriteLine(value);
				    Console.WriteLine(e);
				    //ignore
			    }
			    
			    use_slash = true;
			    usebrac = true;
			    if (Largest is null || Current.PixelHeight > Largest.PixelHeight)
			    {
				    lh = Current.PixelHeight;
				    Largest = Current;
			    }
			    
			    if (n)
			    {
				    lines++;
				    char_x = 0f;
				    max_lh += lh;
				    MaxLineSizes.Add(new(new((int)lw,(int)lh), Largest));
				    max_lh += (uint) ((double) lh * ((double) Largest.CurrentFonts[0].Face.Height / (double) Largest.CurrentFonts[0].Face.UnitsPerEM) * (double) this.Scale);
				    Largest = null;
				    lw = 0;
				    lh = 0;
				    sb.Append(c);
			    }
			    else
			    {
				    Character ch;
				    if (Window is not null) ch = Texture.GetChar(Font, c, Window.Context);
				    else ch = Texture.GetChar(Font, c);
				    if (MaxSize is not null && i > 0 && text[i-1] == ' ')
				    {
					    int addc = 0;
					    float word_char_x = char_x;
					    while (true)
					    {
						    if (addc + i == Text.Length) break;
						    if (text[addc + i] == ' ') break;
						    Character ch2;
						    if (Window is not null) ch2 = Texture.GetChar(Font, text[addc + i], Window.Context);
						    else ch2 = Texture.GetChar(Font, c);
						    word_char_x += (ch2.Advance >> 6) * Scale;
						    if (word_char_x > MaxSize.Value.X)
						    {
							    char_x = 0f;
							    lines++;
							    sb.Append('\n');
							    break;
						    }
						    addc++;
					    }
				    }

				    sb.Append(c);
				    float w = ch.Size.X * Scale;
				    float xrel = char_x + ch.Bearing.X * Scale;
				    char_x += (ch.Advance >> 6) * Scale;
				    if ((xrel + w) >= max_x) max_x = (xrel + w);
				    if ((xrel + w) >= lw) lw = (xrel + w);
			    }
		    }

		    if (Largest is not null)
		    {
			    MaxLineSizes.Add(new(new((int)lw,(int)lh), Largest));
			    max_lh += (uint) ((double) lh * ((double) Largest.CurrentFonts[0].Face.Height / (double) Largest.CurrentFonts[0].Face.UnitsPerEM) * (double) this.Scale);
		    }
		    Largest = null;
		    
		    PlainText = sb.ToString();
		    text_Calculated = sb.ToString();
			Commands.Sort((x, y) => x.Item2.CompareTo(y.Item2));
			
		    Size = new((int)max_x, (int)(max_lh) + (int)(lines * Font.ExtraLinePixels));
		    if (Loaded)
		    {
			    if (Window is not null && Window.CanControleUpdate)
			    {
				    if (!Window.Context.IsCurrent)
				    {
					    try
					    {
						    Window.Context.MakeCurrent();
						    GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
							
					    }
					    catch (Exception e)
					    {
						    Console.WriteLine(e);
					    }
				    }

				    if (Window.Context.IsCurrent)
				    {
					    Parent!.TryDraw();
				    }
			    }
		    }
	    }
    }

    public static Color4[] Rainbow = new[]
    {
	    Color4.Red,
	    new(255,154,0,255),
	    new(208, 222, 33, 255),
	    new(79, 220, 74, 255),
	    new(63, 218, 216, 255),
	    new(47, 201, 226, 255),
	    new(28, 127, 238, 255),
	    new(95, 21, 242, 255),
	    new(186, 12, 248, 255),
	    new(251, 7, 217, 255)
    };
    
    public static Color4 LinkColor = Color4.Cyan;

    private List<SubHitBox> Links = new();
    

    public override void Draw(int x, int y, int sx, int sy, int sw, int sh)
    {
        if (Visible && Loaded)
		{
			if (!Window!.Context.IsCurrent) Window.Context.MakeCurrent();
			Shader.Use();
			GL.Enable(EnableCap.Blend);
			GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
			GL.BlendFunc(0, BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
			Shader.SetMatrixF4("projection", Window.WindowSizeMatrix);

			GL.BindVertexArray(VAO);

			float angle_rad = (float)Math.Atan2(DIR.Y, DIR.X);
			Matrix4 rotateM = Matrix4.CreateRotationZ(angle_rad);
			Matrix4 transOriginM = Matrix4.CreateTranslation(new Vector3(loc_.X + Parent!.IntToWindow(0), loc_.Y + (MaxLineSizes[0].Item1.Y * Scale) + Parent!.IntToWindow(0, true), 0f));
			float char_x = 0.0f;
			Matrix4 staticTransform = rotateM * transOriginM;
			GL.UniformMatrix4(Shader.GetUniformLocation("model"), false, ref staticTransform);
			
			GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
			
			float hhh = 0;
			int NextCommand = 0;
			List<int> Active_Grads = new();
			List<int> Active_Fonts = new();
			List<Vector2i> Active_Links = new();
			Dictionary<int, FontSize> Olds = new();
			int line = 0;
			int count = 0;
			for (int i = 0; i < text_Calculated.Length; i++)
			{
				FontInteraction charfont = Font;
				while (Commands.Count != 0 && NextCommand < Commands.Count && i == Commands[NextCommand].Item2)
				{
					switch (Commands[NextCommand].Item1)
					{
						case TextCode.Gradient or TextCode.Rainbow or TextCode.Color:
							Active_Grads.Add(NextCommand);
							break;
						case TextCode.Font:
							Active_Fonts.Add(NextCommand);
							break;
						case TextCode.url:
							Active_Grads.Add(NextCommand);
							Active_Links.Add(new((int)char_x, (int)hhh));
							break;
					}
					NextCommand++;
				}
				
				if (Active_Fonts.Count != 0)
				{
					int g = Active_Fonts[Active_Fonts.Count - 1];
					Tuple<TextCode, int, int ,object?> com = Commands[g];
					
					if (com.Item1 == TextCode.Font)
					{
						charfont = (FontInteraction)com.Item4!;
					}
					
					if (com.Item3 <= i)
					{
						Active_Fonts.RemoveAt(Active_Fonts.Count-1);
					}
				}

				if (Active_Grads.Count != 0)
				{
					Tuple<TextCode, int, int ,object?> com = Commands[Active_Grads[Active_Grads.Count - 1]];
					(Color4, Color4) col;
					
					if (com.Item1 == TextCode.Rainbow)
					{
						Tuple<GradType, int, int> item4 = (Tuple<GradType, int, int>)com.Item4!;
						col = getGradcols(com.Item2, i, com.Item3, 0,line, item4.Item3, item4.Item1, Rainbow);
					}
					else if (com.Item1 == TextCode.Color)
					{
						Tuple<Color4, BlendType> item4 = (Tuple<Color4, BlendType>)com.Item4!;
						if (item4.Item2 == BlendType.MultiplyAlpha)
						{
							_alpha = item4.Item1.A;
							col = getGradcols(com.Item2, i, com.Item3, 0, line, 0, GradType.Block,
								new Color4[] { DefaultColor, DefaultColor });
						}
						else
						{
							col = new(item4.Item1, item4.Item1);
						}
						
					}
					else if (com.Item1 == TextCode.url)
					{
						col = new(LinkColor, LinkColor);
					}
					else
					{
						Tuple<Color4[], GradType, int, int> item4 = (Tuple<Color4[], GradType, int, int>)com.Item4!;
						col = getGradcols(com.Item2, i, com.Item3, item4.Item4, line, item4.Item4, item4.Item2, item4.Item1);
					}
					GL.Uniform4(Shader.GetUniformLocation("textColor"), col.Item1);
					GL.Uniform4(Shader.GetUniformLocation("rightColor"), col.Item2);
					if (com.Item3 == i)
					{
						if (com.Item1 == TextCode.url)
						{
							int index = Active_Links.Count - 1;
							Vector2i now = new((int)char_x, (int)hhh);
							Vector2i lc = Active_Links[index];
							Vector2i sz = new(now.X - Active_Links[Active_Links.Count - 1].X,
								MaxLineSizes[line].Item1.Y);
							if (Links.Count <= index || Links[index].Location != Active_Links[index] || Links[index].Size != sz)
							{
								if (Links.Count > count)Links.RemoveAt(count);
								
								SubHitBox hb = new()
								{
									Location = lc,
									Size = sz,
									HoverMouse = MouseCursor.Hand
								};
								hb.Clicked += _ =>
								{
									try
									{
										if (OperatingSystem.IsWindows())
											Process.Start((string)com.Item4!);
										else if (OperatingSystem.IsLinux())
										{
											Process.Start("xdg-open", (string)com.Item4!);
										}
									}
									catch (Exception e)
									{
										Console.WriteLine(e);
									}

									return Task.CompletedTask;
								};
								Links.Insert(count, hb);
								SubHitBoxes.Add(hb);
								count++;
							}
							
							Active_Links.RemoveAt(Active_Links.Count-1);
						}

						Tuple<TextCode, int, int, object?> com2 = Commands[Active_Grads[Active_Grads.Count - 1]];
						if (com2.Item1 == TextCode.Color)
						{
							Tuple<Color4, BlendType> item4 = (Tuple<Color4, BlendType>)com.Item4!;
							if (item4.Item2 == BlendType.MultiplyAlpha) _alpha = 1;
						}
						Active_Grads.RemoveAt(Active_Grads.Count-1);
					}
				}
				else
				{
					GL.Uniform4(Shader.GetUniformLocation("textColor"), DefaultColor);
					GL.Uniform4(Shader.GetUniformLocation("rightColor"), DefaultColor);
				}
				
				
				char c;
				if (PasswordChar is null)
					c = text_Calculated[i];
				else
					c = PasswordChar.Value;
				bool n = (c == '\n');
				if ((!_characters[Window!.Context].ContainsKey(charfont) || !_characters[Window!.Context][charfont].ContainsKey(c) ) && !n)
				{
					_ = Texture.TextureForChar(Window!.Context, charfont, c, Shader);
				}
				
                if (n)
                {
	                hhh += ((float)MaxLineSizes[line].Item1.Y *
	                        ((float)MaxLineSizes[line].Item2.CurrentFonts[0].Face.Height /
	                         (float)MaxLineSizes[line].Item2.CurrentFonts[0].Face.UnitsPerEM) * (float)this.Scale);
	                hhh += Font.ExtraLinePixels;
                	char_x = 0f;
	                line++;
                }
                else
                {
	                if (!_characters[Window!.Context][charfont].ContainsKey(c)) continue;
	                Character ch = _characters[Window!.Context][charfont][c];
					
                	float w = ch.Size.X * Scale;
                	float h = ch.Size.Y * Scale;
                	float xrel = char_x + ch.Bearing.X * Scale;
                	float yrel = (ch.Size.Y - ch.Bearing.Y) * Scale;
                	yrel += hhh;
                	char_x += (ch.Advance >> 6) * Scale;
     
	                GL.Uniform2(Shader.GetUniformLocation("scale"), w, h);
	                GL.Uniform2(Shader.GetUniformLocation("offset"), xrel, yrel);
	                
                	ch.Texture.Use();

                	GL.DrawArrays(PrimitiveType.Triangles, 0, 6);
                }
			}
        }
    }
}