201 lines
6.1 KiB
C#
Executable File
201 lines
6.1 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 SharpFont;
|
|
using Encoding = SharpFont.Encoding;
|
|
|
|
namespace GraphicsManager.Objects;
|
|
|
|
public class Label : IRenderObject
|
|
{
|
|
public static readonly Shader DefaultTextShader = new("Label", true);
|
|
public static readonly Font DefaultFont = new();
|
|
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; } }
|
|
public bool Visible { get; set; } = true;
|
|
|
|
public static readonly Dictionary<Font, Dictionary<uint, Character>> _characters = new();
|
|
private string text = string.Empty;
|
|
public int VAO { get; private set; }
|
|
public int VBO { get; private set; }
|
|
public Vector2 DIR { get; set; } = new Vector2(1f, 0f);
|
|
public string Text
|
|
{
|
|
get => text;
|
|
set
|
|
{
|
|
text = value;
|
|
if (Loaded)
|
|
{
|
|
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
|
|
if (!_characters.ContainsKey(Font)) _characters.Add(Font, new Dictionary<uint, Character>());
|
|
float addy = Font.PixelHeight * Scale, addx = 0F, char_x = 0F, hhh = 0F;
|
|
foreach (char character in value)
|
|
{
|
|
if (!_characters[Font].ContainsKey(character))
|
|
{
|
|
var f = Texture.TextureForChar(Font, character, Font.Faces.ToArray());
|
|
f.LoadText();
|
|
}
|
|
float w = _characters[Font][character].Size.X * Scale;
|
|
float xrel = char_x + _characters[Font][character].Bearing.X * Scale;
|
|
if (character == '\n')
|
|
{
|
|
hhh += Font.PixelHeight;
|
|
char_x = 0f;
|
|
addy += Font.PixelHeight * Scale;
|
|
}
|
|
char_x += (_characters[Font][character].Advance >> 6) * Scale;
|
|
if (xrel + w > addx) addx = xrel + w;
|
|
}
|
|
|
|
Size = new((int)addx, (int)addy);
|
|
if (Window is not null && Window.CanControleUpdate && Loaded) Parent!.TryDraw();
|
|
}
|
|
}
|
|
}
|
|
public Shader Shader { get; set; } = DefaultTextShader;
|
|
public Font Font { get; set; } = DefaultFont;
|
|
public float Scale { get; set; } = 1.0f;
|
|
public Vector4 Color { get; set; } = new Vector4(1, 1, 1, 1);
|
|
public Vector2i Distance { get; private set; }
|
|
private Vector2i loc_ = new();
|
|
private Vector2i locc_ = new();
|
|
public Vector2i Location
|
|
{
|
|
get
|
|
{
|
|
return loc_;
|
|
}
|
|
set
|
|
{
|
|
loc_ = value;
|
|
if (Window is null || Parent is null) return;
|
|
locc_ = new((int)Window.FloatToInt(Parent.IntToFloat(value.X)), (int)Window.FloatToInt(Parent.IntToFloat(value.Y + (int)Font.PixelHeight, true), true));
|
|
if (Window.CanControleUpdate && Loaded) Parent!.TryDraw();
|
|
}
|
|
}
|
|
public Vector2i Size { get; set; }
|
|
|
|
public void Clean()
|
|
{
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
|
|
}
|
|
|
|
public void Draw()
|
|
{
|
|
if (Visible & Loaded)
|
|
{
|
|
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(locc_.X, locc_.Y, 0f));
|
|
|
|
float char_x = 0.0f;
|
|
|
|
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
|
|
GL.ActiveTexture(TextureUnit.Texture0);
|
|
|
|
float hhh = 0f;
|
|
foreach (char c in Text)
|
|
{
|
|
if (!_characters[Font].ContainsKey(c)) break;
|
|
Character ch = _characters[Font][c];
|
|
int maxx = 0;
|
|
int maxy = (int)Font.PixelHeight;
|
|
if (c == '\n')
|
|
{
|
|
hhh += Font.PixelHeight;
|
|
char_x = 0f;
|
|
maxy += (int)Font.PixelHeight;
|
|
}
|
|
else
|
|
{
|
|
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;
|
|
if (xrel + w > maxx) maxx = (int)(xrel + w);
|
|
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);
|
|
}
|
|
|
|
}
|
|
|
|
GL.Disable(EnableCap.Blend);
|
|
}
|
|
}
|
|
public Window? Window { get; private set; }
|
|
|
|
public void LoadToParent(IParent window, Window win)
|
|
{
|
|
if (Loaded) return;
|
|
if (!_characters.ContainsKey(Font)) _characters.Add(Font, new Dictionary<uint, Character>());
|
|
Parent = window;
|
|
Window = win;
|
|
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
|
|
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 4);
|
|
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
|
|
};
|
|
|
|
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(window.Size.X - Size.X - Location.X, window.Size.Y - Size.Y - Location.Y);
|
|
if (WindowLoaded is not null) WindowLoaded.Invoke(this);
|
|
}
|
|
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;
|
|
}
|