244 lines
8.3 KiB
C#
244 lines
8.3 KiB
C#
using System.Reflection;
|
|
using System.Runtime.InteropServices;
|
|
using BlurgText;
|
|
using Dashboard.Drawing.OpenGL.Text;
|
|
using OpenTK.Graphics.OpenGL;
|
|
using OpenTK.Mathematics;
|
|
|
|
namespace Dashboard.Drawing.OpenGL.Executors
|
|
{
|
|
public class TextCommandExecutor : ICommandExecutor, IInitializer
|
|
{
|
|
public IEnumerable<string> Extensions { get; } = new[] { "DB_Text" };
|
|
public IContextExecutor Executor { get; private set; }
|
|
private BlurgEngine Engine => Executor.ResourcePool.GetResourceManager<BlurgEngine>();
|
|
public bool IsInitialized { get; private set; }
|
|
|
|
private DrawCallRecorder _recorder;
|
|
private int _program = 0;
|
|
private int _transformsLocation = -1;
|
|
private int _atlasLocation = -1;
|
|
private int _borderWidthLocation = -1;
|
|
private int _borderColorLocation = -1;
|
|
private int _fillColorLocation = -1;
|
|
|
|
public TextCommandExecutor()
|
|
{
|
|
Executor = null!;
|
|
_recorder = new DrawCallRecorder(this);
|
|
}
|
|
|
|
public void Initialize()
|
|
{
|
|
if (IsInitialized)
|
|
return;
|
|
IsInitialized = true;
|
|
|
|
Assembly self = typeof(TextCommandExecutor).Assembly;
|
|
|
|
using Stream vsource = self.GetManifestResourceStream("Dashboard.Drawing.OpenGL.Executors.text.vert")!;
|
|
using Stream fsource = self.GetManifestResourceStream("Dashboard.Drawing.OpenGL.Executors.text.frag")!;
|
|
int vs = ShaderUtil.CompileShader(ShaderType.VertexShader, vsource);
|
|
int fs = ShaderUtil.CompileShader(ShaderType.FragmentShader, fsource);
|
|
_program = ShaderUtil.LinkProgram(vs, fs, new []
|
|
{
|
|
"a_v3Position",
|
|
"a_v2TexCoords",
|
|
});
|
|
GL.DeleteShader(vs);
|
|
GL.DeleteShader(fs);
|
|
|
|
_transformsLocation = GL.GetUniformLocation(_program, "m4Transforms");
|
|
_atlasLocation = GL.GetUniformLocation(_program, "txAtlas");
|
|
_borderWidthLocation = GL.GetUniformLocation(_program, "fBorderWidth");
|
|
_borderColorLocation = GL.GetUniformLocation(_program, "v4BorderColor");
|
|
_fillColorLocation = GL.GetUniformLocation(_program, "v4FillColor");
|
|
|
|
_recorder.Initialize();
|
|
}
|
|
|
|
public void SetContextExecutor(IContextExecutor executor)
|
|
{
|
|
Executor = executor;
|
|
}
|
|
|
|
public void BeginFrame()
|
|
{
|
|
}
|
|
|
|
public void BeginDraw()
|
|
{
|
|
_recorder.Clear();
|
|
}
|
|
|
|
public void EndDraw()
|
|
{
|
|
GL.UseProgram(_program);
|
|
GL.Enable(EnableCap.Blend);
|
|
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
|
|
_recorder.Execute();
|
|
GL.Disable(EnableCap.Blend);
|
|
}
|
|
|
|
public void EndFrame()
|
|
{
|
|
}
|
|
|
|
public void ProcessCommand(ICommandFrame frame)
|
|
{
|
|
switch (frame.Command.Name)
|
|
{
|
|
case "Text":
|
|
DrawText(frame);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void DrawText(ICommandFrame frame)
|
|
{
|
|
TextCommandArgs args = frame.GetParameter<TextCommandArgs>();
|
|
DbBlurgFont font = Engine.InternFont(args.Font);
|
|
|
|
BlurgColor color;
|
|
switch (args.TextBrush)
|
|
{
|
|
case SolidBrush solid:
|
|
color = new BlurgColor()
|
|
{
|
|
R = solid.Color.R,
|
|
G = solid.Color.G,
|
|
B = solid.Color.B,
|
|
A = solid.Color.A,
|
|
};
|
|
break;
|
|
default:
|
|
color = new BlurgColor() { R = 255, G = 0, B = 255, A = 255 };
|
|
break;
|
|
}
|
|
|
|
BlurgResult? result = Engine.Blurg.BuildString(font.Font, font.Size, color, args.Text);
|
|
|
|
if (result == null)
|
|
return;
|
|
|
|
Vector3 position = new Vector3(args.Position.X, args.Position.Y, args.Position.Z);
|
|
ExecuteBlurgResult(result, position);
|
|
|
|
result.Dispose();
|
|
}
|
|
|
|
private void ExecuteBlurgResult(BlurgResult result, Vector3 position)
|
|
{
|
|
Matrix4 transforms = Executor.TransformStack.Top;
|
|
|
|
for (int i = 0; i < result.Count; i++)
|
|
{
|
|
BlurgRect rect = result[i];
|
|
|
|
int texture = (int)rect.UserData;
|
|
Vector4 color = new Vector4(rect.Color.R / 255f, rect.Color.G / 255f, rect.Color.B / 255f,
|
|
rect.Color.A / 255f);
|
|
|
|
if (i == 0)
|
|
{
|
|
_recorder.Begin(PrimitiveType.Triangles, new Call()
|
|
{
|
|
Texture = texture,
|
|
FillColor = color,
|
|
Transforms = transforms,
|
|
});
|
|
}
|
|
else if (
|
|
_recorder.CurrentCall.Texture != texture ||
|
|
_recorder.CurrentCall.FillColor != color)
|
|
{
|
|
_recorder.End();
|
|
Call call = new Call()
|
|
{
|
|
Texture = texture,
|
|
FillColor = color,
|
|
Transforms = transforms,
|
|
};
|
|
_recorder.Begin(PrimitiveType.Triangles, call);
|
|
}
|
|
|
|
Vector3 p00 = new Vector3(rect.X, rect.Y, 0) + position;
|
|
Vector3 p10 = p00 + new Vector3(rect.Width, 0, 0);
|
|
Vector3 p11 = p00 + new Vector3(rect.Width, rect.Height, 0);
|
|
Vector3 p01 = p00 + new Vector3(0, rect.Height, 0);
|
|
|
|
Vector2 uv00 = new Vector2(rect.U0, rect.V0);
|
|
Vector2 uv10 = new Vector2(rect.U1, rect.V0);
|
|
Vector2 uv11 = new Vector2(rect.U1, rect.V1);
|
|
Vector2 uv01 = new Vector2(rect.U0, rect.V1);
|
|
|
|
_recorder.Vertex(p00, uv00);
|
|
_recorder.Vertex(p10, uv10);
|
|
_recorder.Vertex(p11, uv11);
|
|
|
|
_recorder.Vertex(p00, uv00);
|
|
_recorder.Vertex(p11, uv11);
|
|
_recorder.Vertex(p01, uv01);
|
|
}
|
|
_recorder.End();
|
|
}
|
|
|
|
private struct Call
|
|
{
|
|
public Matrix4 Transforms = Matrix4.Identity;
|
|
public int Texture = 0;
|
|
public float BorderWidth = 0f;
|
|
public Vector4 FillColor = Vector4.One;
|
|
public Vector4 BorderColor = new Vector4(0,0,0,1);
|
|
|
|
public Call()
|
|
{
|
|
}
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Explicit, Size = 8 * sizeof(float))]
|
|
private struct Vertex
|
|
{
|
|
[FieldOffset(0)]
|
|
public Vector3 Position;
|
|
[FieldOffset(4 * sizeof(float))]
|
|
public Vector2 TexCoords;
|
|
}
|
|
|
|
private class DrawCallRecorder : DrawCallRecorder<Call, Vertex>
|
|
{
|
|
private TextCommandExecutor Executor { get; }
|
|
|
|
public DrawCallRecorder(TextCommandExecutor executor)
|
|
{
|
|
Executor = executor;
|
|
}
|
|
|
|
public void Vertex(Vector3 position, Vector2 texCoords)
|
|
{
|
|
Vertex(new Vertex(){Position = position, TexCoords = texCoords});
|
|
}
|
|
|
|
protected override void PrepareCall(in Call call)
|
|
{
|
|
Matrix4 transforms = call.Transforms;
|
|
GL.UniformMatrix4f(Executor._transformsLocation, 1, true, ref transforms);
|
|
GL.Uniform1f(Executor._borderWidthLocation, call.BorderWidth);
|
|
GL.Uniform4f(Executor._borderColorLocation, 1, in call.BorderColor);
|
|
GL.Uniform4f(Executor._fillColorLocation, 1, in call.FillColor);
|
|
GL.Uniform1i(Executor._atlasLocation, 0);
|
|
GL.ActiveTexture(TextureUnit.Texture0);
|
|
GL.BindTexture(TextureTarget.Texture2d, call.Texture);
|
|
}
|
|
|
|
protected override void SetVertexFormat()
|
|
{
|
|
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, VertexSize, 0);
|
|
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, VertexSize, 4*sizeof(float));
|
|
GL.EnableVertexAttribArray(0);
|
|
GL.EnableVertexAttribArray(1);
|
|
}
|
|
}
|
|
}
|
|
}
|