JacobTech 448e0f670f Bugs & Features.
Mainly bug fixes with a few new shaders and controls.
2023-08-21 10:57:06 -04:00

495 lines
14 KiB
C#
Executable File

using GraphicsManager.Enums;
using GraphicsManager.Interfaces;
using GraphicsManager.Objects.Core;
using GraphicsManager.Structs;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Common.Input;
using OpenTK.Windowing.Desktop;
using OpenTK.Windowing.GraphicsLibraryFramework;
using SharpFont;
using Encoding = SharpFont.Encoding;
namespace GraphicsManager.Objects;
public class RainbowLabel : ILabel
{
public RainbowLabel(FontFamily fontFamily)
{
Font = FontInteraction.Load(fontFamily);
}
public RainbowLabel(FontInteraction interaction)
{
Font = interaction;
}
public ContextMenu? ContextMenu { get; set; } = null;
public IParent? Parent { get; private set; }
public ObjectAnchor Anchor { get; set; } = ObjectAnchor.Left | ObjectAnchor.Top;
private Vector2 laf = new(), saf = new();
public Vector2 LocationAsFloat { get { return laf; } }
public Vector2 SizeAsFloat { get { return saf; } }
private char? pc = null;
public char? PasswordChar
{
get => pc;
set
{
pc = value;
if (Parent is not null) Parent.TryDraw();
}
}
private bool _Visible = true;
public bool Visible
{
get => _Visible;
set
{
_Visible = value;
if (Parent is not null && Loaded) Parent.TryDraw();
}
}
private string text = string.Empty;
public int VAO { get; private set; }
public void Focus()
{
}
public void UnFocus()
{
}
public int VBO { get; private set; }
public Vector2 DIR { get; set; } = new Vector2(1f, 0f);
public int TrueHeight = 0;
public int PostiveTrueHeight = 0;
public Vector2i GetSizeOfChar(int Index)
{
float addy = Font.PixelHeight * Scale, addx = 0F, char_x = 0F;
for (int i = 0; i < Index + 1; i++)
{
char character;
if (PasswordChar is null)
character = Text[i];
else
character = PasswordChar.Value;
if (character == '\n')
{
char_x = 0f;
addy += Font.PixelHeight * Scale;
addy += Font.ExtraLinePixels;
continue;
}
Character cha = Texture.GetChar(Font.CurrentFont, character, Font.PixelHeight);
float w = cha.Size.X * Scale;
float xrel = char_x + cha.Bearing.X * Scale;
char_x += (cha.Advance >> 6) * Scale;
if ((xrel + w) >= addx) addx = (xrel + w);
}
return new((int)addx, (int)addy);
}
public string Text
{
get => text;
set
{
if (value is null) value = string.Empty;
text = value;
int line = 0;
double nl = 0;
double addy = 0f, addy2 =0f, addx = 0F, char_x = 0F;
for (int i = 0; i < value.Length; i++)
{
char character;
if (PasswordChar is null)
character = value[i];
else
character = PasswordChar.Value;
if (character == '\n')
{
char_x = 0f;
nl = addy;
line++;
continue;
}
Character cha = Texture.GetChar(Font.CurrentFont, character, Font.PixelHeight);
double w = cha.Size.X * Scale;
double xrel = char_x + cha.Bearing.X * Scale;
double yrel = ((cha.Size.Y - cha.Bearing.Y) * Scale) + (Font.PixelHeight * Scale);
yrel += nl;
char_x += (cha.Advance >> 6) * Scale;
if ((xrel + w) >= addx) addx = (xrel + w);
if (yrel > addy) addy = yrel;
if (line == 0)
{
if (addy2 < cha.Bearing.Y) addy2 = cha.Bearing.Y;
}
}
Size = new((int)addx, (int)addy);
PostiveTrueHeight = (int)addy2;
TrueHeight = (int)(addy - (Font.PixelHeight - addy2));
if (Loaded)
{
if (Window is not null && Window.CanControleUpdate)
{
if (!Window.Context.IsCurrent)
{
try
{
Window.Context.MakeCurrent();
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
Parent!.TryDraw();
}
}
}
}
public Shader Shader { get; set; } = null!;
public FontInteraction Font { get; }
public float Scale { get; set; } = 1.0f;
public Color4 Color { get; set; } = new Color4(255, 255, 255, 255);
public Vector2i Distance { get; set; }
private Vector2i loc_ = new();
private int maxy = 0, maxx = 0;
public Vector2i Location
{
get
{
return loc_;
}
set
{
loc_ = value;
if (Window is null || Parent is null) return;
if (Window.CanControleUpdate && Loaded)
{
// = Parent.GetParentRelLocPoint() + new Vector2i(Location.X, Parent.Size.Y - (loc_.Y + Size.Y));
Parent!.TryDraw();
if (!Window.Context.IsCurrent) Window.Context.MakeCurrent();
}
}
}
private Vector2i _size;
public Vector2i Size { get => _size;
set
{
_size = value;
//if (Loaded && Parent is not null) ScissorLocation = Parent.GetParentRelLocPoint() + new Vector2i(Location.X, Parent.Size.Y - (loc_.Y + Size.Y));
}
}
public void Clean()
{
Tuple<int, int, int> tup = GlobalBuffers[Window!.Context];
if (tup.Item3 - 1 == 0)
{
//Broken, I may fix latter
//if (!Window.Context.IsCurrent) Window.Context.MakeCurrent();
//GL.DeleteBuffer(VBO);
//GL.DeleteVertexArray(VAO);
//GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
//GlobalBuffers.Remove(Window!.Context);
}
else
{
GlobalBuffers[Window!.Context] = new(tup.Item1, tup.Item2, tup.Item3 - 1);
}
Size = new(0, 0);
Loaded = false;
Visible = false;
}
public Vector2i ScissorLocation { get; private set; }
public void Draw(int x, int y, int ww, int hh)
{
if (Visible && Loaded && this.Font is not null)
{
if (!Window!.Context.IsCurrent) Window.Context.MakeCurrent();
Shader.Use();
GL.Enable(EnableCap.Blend);
//GL.Uniform4(2, Color);
Matrix4 projectionM = Matrix4.CreateOrthographicOffCenter(0, Window!.Size.X, Window!.Size.Y, 0, -1.0f, 1.0f);
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
GL.BlendFunc(0, BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
GL.UniformMatrix4(1, false, ref projectionM);
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 + Window.FloatToInt(Parent!.IntToFloat(0)), loc_.Y + (Font.PixelHeight * Scale) + Window.FloatToInt(Parent!.IntToFloat(0, true), true), 0f));
float char_x = 0.0f;
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
GL.ActiveTexture(TextureUnit.Texture0);
float hhh = 0f;
for (int i = 0; i < Text.Length; i++)
{
var col = SetCol(i);
GL.Uniform4(2, col);
char c;
if (PasswordChar is null)
c = Text[i];
else
c = PasswordChar.Value;
bool n = (c == '\n');
if (!Label._characters[Window!.Context][Font].ContainsKey(c) && !n)
{
Texture f = Texture.TextureForChar(Window!.Context, Font, c);
}
int maxx = 0;
if (n)
{
hhh += Font.PixelHeight * Scale;
hhh += Font.ExtraLinePixels;
char_x = 0f;
}
else
{
if (!Label._characters[Window!.Context][Font].ContainsKey(c)) continue;
Character ch = Label._characters[Window!.Context][Font][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;
Matrix4 scaleM = Matrix4.CreateScale(new Vector3(w, h, 1.0f));
Matrix4 transRelM = Matrix4.CreateTranslation(new Vector3(xrel, yrel, 0.0f));
Matrix4 modelM = scaleM * transRelM * rotateM * transOriginM;
GL.UniformMatrix4(0, false, ref modelM);
ch.Texture.Use();
GL.DrawArrays(PrimitiveType.Triangles, 0, 6);
}
}
}
}
public void ForceDistanceUpdate()
{
}
public void ForceDistanceUpdate(IParent parent)
{
}
public Color4 SetCol(int index)
{
double onefith = Math.Round((double)Text.Length / 5);
double twofith = Math.Round(onefith * 2);
double threefith = Math.Round(onefith * 3);
double fourfith = Math.Round(onefith * 4);
if (onefith < 1)
{
return Text.Length switch
{
1 => new Color4(255,0,0,255),
2 => index switch
{
0 => new Color4(255, 0, 0, 255),
1 => new Color4(255, 255, 0, 255)
},
3 => index switch
{
0 => new Color4(255, 0, 0, 255),
1 => new Color4(255, 255, 0, 255),
2 => new Color4(0, 255, 0, 255)
},
4 => index switch
{
0 => new Color4(255, 0, 0, 255),
1 => new Color4(255, 255, 0, 255),
2 => new Color4(0, 255, 0, 255),
3 => new Color4(0, 255, 255, 255)
},
5 => index switch
{
0 => new Color4(255, 0, 0, 255),
1 => new Color4(255, 255, 0, 255),
2 => new Color4(0, 255, 0, 255),
3 => new Color4(0, 255, 255, 255),
4 => new Color4(0, 0, 255, 255)
}
};
}
else
{
double n = index + 1;
if (n <= onefith)
{
n = index / onefith;
if (n > 1) n = 1;
return new Color4(255, (byte)(n * 255),0,255);
}
else if (n <= twofith)
{
n = (index - onefith) / onefith;
if (n > 1) n = 1;
return new Color4((byte)(255 - (n * 255)), 255,0,255);
}
else if (n <= threefith)
{
n = (index - twofith) / onefith;
if (n > 1) n = 1;
return new Color4(0, 255,(byte)(n * 255),255);
}
else if (n <= fourfith)
{
n = (index - threefith) / onefith;
if (n > 1) n = 1;
return new Color4(0, (byte)(255 - (n * 255)),255,255);
}
else
{
n = (index - fourfith) / onefith;
if (n > 1)
{
n -= 1;
return new Color4(255, 0,(byte)(255 - (n * 255)),255);
}
else return new Color4((byte)(n * 255), 0,255,255);
}
}
}
public Window? Window { get; private set; }
private static Dictionary<IGLFWGraphicsContext, Tuple<int, int, int>> GlobalBuffers = new();
public void LoadToParent(IParent window, Window win)
{
if (Loaded) return;
if (!Label._characters.ContainsKey(win!.Context)) Label._characters.Add(win!.Context, new());
if (!Label._characters[win!.Context].ContainsKey(Font)) Label._characters[win!.Context].Add(Font, new Dictionary<uint, Character>());
if (Shader is null) Shader = Label.DefaultTextShader[win.Context];
Parent = window;
Window = win;
Window.MouseMove += WindowOnMouseMove;
Window.MouseDown += WindowOnMouseDown;
if (!Window!.Context.IsCurrent) Window.Context.MakeCurrent();
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 4);
if (!GlobalBuffers.ContainsKey(win.Context))
{
float[] vquad =
{
0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
0.0f, -1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f
};
int _VBO = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, _VBO);
GL.BufferData(BufferTarget.ArrayBuffer, 4 * 6 * 4, vquad, BufferUsageHint.StaticDraw);
int _VAO = GL.GenVertexArray();
GL.BindVertexArray(_VAO);
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 4 * 4, 0);
GL.EnableVertexAttribArray(1);
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 4 * 4, 2 * 4);
GlobalBuffers.Add(win.Context, new(_VBO, _VAO, 0));
}
Tuple<int, int, int> tup = GlobalBuffers[win.Context];
VBO = tup.Item1;
VAO = tup.Item2;
GlobalBuffers[win.Context] = new(VBO, VAO, tup.Item3 + 1);
/*
VBO = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, VBO);
GL.BufferData(BufferTarget.ArrayBuffer, 4 * 6 * 4, vquad, BufferUsageHint.StaticDraw);
VAO = GL.GenVertexArray();
GL.BindVertexArray(VAO);
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 4 * 4, 0);
GL.EnableVertexAttribArray(1);
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 4 * 4, 2 * 4);
*/
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.BindVertexArray(0);
Loaded = true;
Text = Text;
Location = Location;
Distance = new(Parent.Size.X - Size.X - Location.X, Parent.Size.Y - Size.Y - Location.Y);
if (WindowLoaded is not null) WindowLoaded.Invoke(this);
}
private void WindowOnMouseDown(MouseButtonEventArgs obj)
{
if (mouseinside && obj.Button == MouseButton.Button1 && Clicked is not null) _ = Clicked.Invoke(this);
if (mouseinside && obj.Button == MouseButton.Button2 && ContextMenu is not null) ContextMenu.ShowContext(Window!);
if (!mouseinside && ContextMenu is not null) ContextMenu.HideContext(Window!);
}
public MouseCursor HoverMouse { get; set; } = MouseCursor.Default;
private bool mouseinside = false;
private void WindowOnMouseMove(MouseMoveEventArgs obj)
{
if (Visible &&
Parent?.IntToFloat(Location.X) <= Window?.IntToFloat((float)Window?.MousePosition.X!) &&
Parent?.IntToFloat(Size.X + Location.X) >= Window?.IntToFloat((float)Window?.MousePosition.X!) &&
Parent?.IntToFloat(Location.Y + Size.Y, true) <= Window?.IntToFloat((float)Window?.MousePosition.Y!, true) &&
Parent?.IntToFloat(Location.Y, true) >= Window?.IntToFloat((float)Window?.MousePosition.Y!, true))
{
if (!mouseinside)
{
if (Window!.CurrentTop is null || Window!.CurrentTop == this)
{
Window!.Cursor = HoverMouse;
if (MouseEnter is not null) _ = MouseEnter.Invoke(this);
mouseinside = true;
}
else
{
mouseinside = false;
}
}
}
else
{
if (mouseinside)
{
if (mouseinside && Window!.Cursor == HoverMouse) Window!.Cursor = Parent!.HoverMouse;
if (MouseLeave is not null && mouseinside) _ = MouseLeave.Invoke(this);
mouseinside = false;
}
}
}
public event Func<IRenderObject, Task>? Clicked;
public event Func<IRenderObject, Task>? WindowLoaded;
public event Func<IRenderObject, Task>? MouseEnter;
public event Func<IRenderObject, Task>? MouseLeave;
public object? Tag { get; set; } = null;
public bool Loaded { get; private set; } = false;
}