Implement basic commands.
This commit is contained in:
parent
5014d218e2
commit
95cc1648b2
48
Dashboard.Drawing.OpenGL/CommandInfo.cs
Normal file
48
Dashboard.Drawing.OpenGL/CommandInfo.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Dashboard.Drawing.OpenGL
|
||||
{
|
||||
public enum SimpleDrawCommand : int
|
||||
{
|
||||
Point = 1,
|
||||
Line = 2,
|
||||
Rect = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Make sure your custom commands have values higher than this if you plan on using the default command
|
||||
/// buffer.
|
||||
/// </summary>
|
||||
CustomCommandStart = 4096
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 64)]
|
||||
public struct CommandInfo
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public SimpleDrawCommand Type;
|
||||
|
||||
[FieldOffset(4)]
|
||||
public int Flags;
|
||||
|
||||
[FieldOffset(8)]
|
||||
public float Arg0;
|
||||
[FieldOffset(12)]
|
||||
public float Arg1;
|
||||
|
||||
[FieldOffset(16)]
|
||||
public int FgGradientIndex;
|
||||
[FieldOffset(20)]
|
||||
public int FgGradientCount;
|
||||
[FieldOffset(24)]
|
||||
public int BgGradientIndex;
|
||||
[FieldOffset(28)]
|
||||
public int BgGradientCount;
|
||||
|
||||
[FieldOffset(32)]
|
||||
public Vector4 FgColor;
|
||||
|
||||
[FieldOffset(48)]
|
||||
public Vector4 BgColor;
|
||||
}
|
||||
}
|
@ -1,18 +1,47 @@
|
||||
using System.Drawing;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using Dashboard.Drawing.OpenGL.Executors;
|
||||
|
||||
namespace Dashboard.Drawing.OpenGL
|
||||
{
|
||||
public class ContextExecutor : IDisposable
|
||||
public interface ICommandExecutor
|
||||
{
|
||||
IEnumerable<string> Extensions { get; }
|
||||
IContextExecutor Executor { get; }
|
||||
|
||||
void SetContextExecutor(IContextExecutor executor);
|
||||
|
||||
void BeginFrame();
|
||||
|
||||
void BeginDraw();
|
||||
|
||||
void EndDraw();
|
||||
|
||||
void EndFrame();
|
||||
|
||||
void ProcessCommand(ICommandFrame frame);
|
||||
}
|
||||
|
||||
public interface IContextExecutor : IInitializer, IGLDisposable
|
||||
{
|
||||
GLEngine Engine { get; }
|
||||
IGLContext Context { get; }
|
||||
ContextResourcePool ResourcePool { get; }
|
||||
TransformStack TransformStack { get; }
|
||||
}
|
||||
|
||||
public class ContextExecutor : IContextExecutor
|
||||
{
|
||||
public GLEngine Engine { get; }
|
||||
public IGLContext Context { get; }
|
||||
public ContextResourcePool ResourcePool { get; }
|
||||
public TransformStack TransformStack { get; } = new TransformStack();
|
||||
protected bool IsDisposed { get; private set; } = false;
|
||||
|
||||
public bool IsInitialized { get; private set; } = false;
|
||||
|
||||
private int _program = 0;
|
||||
private readonly List<ICommandExecutor> _executorsList = new List<ICommandExecutor>();
|
||||
|
||||
private readonly Dictionary<string, ICommandExecutor> _executorsMap = new Dictionary<string, ICommandExecutor>();
|
||||
|
||||
public ContextExecutor(GLEngine engine, IGLContext context)
|
||||
{
|
||||
Engine = engine;
|
||||
@ -20,11 +49,41 @@ namespace Dashboard.Drawing.OpenGL
|
||||
|
||||
ResourcePool = Engine.ResourcePoolManager.Get(context);
|
||||
ResourcePool.IncrementReference();
|
||||
|
||||
AddExecutor(new BaseCommandExecutor());
|
||||
}
|
||||
|
||||
~ContextExecutor()
|
||||
{
|
||||
DisposeInvoker(false);
|
||||
DisposeInvoker(true, false);
|
||||
}
|
||||
|
||||
public void AddExecutor(ICommandExecutor executor, bool overwrite = false)
|
||||
{
|
||||
if (IsInitialized)
|
||||
throw new Exception("This context executor is already initialized. Cannot add new command executors.");
|
||||
|
||||
IInitializer? initializer = executor as IInitializer;
|
||||
|
||||
if (initializer?.IsInitialized == true)
|
||||
throw new InvalidOperationException("This command executor has already been initialized, cannot add here.");
|
||||
|
||||
if (!overwrite)
|
||||
{
|
||||
foreach (string extension in executor.Extensions)
|
||||
{
|
||||
if (_executorsMap.ContainsKey(extension))
|
||||
throw new InvalidOperationException("An executor already handles this extension.");
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string extension in executor.Extensions)
|
||||
{
|
||||
_executorsMap[extension] = executor;
|
||||
}
|
||||
_executorsList.Add(executor);
|
||||
|
||||
executor.SetContextExecutor(this);
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
@ -33,32 +92,56 @@ namespace Dashboard.Drawing.OpenGL
|
||||
return;
|
||||
IsInitialized = true;
|
||||
|
||||
LoadShaders();
|
||||
foreach (ICommandExecutor executor in _executorsList)
|
||||
{
|
||||
if (executor is IInitializer initializer)
|
||||
initializer.Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadShaders()
|
||||
public virtual void BeginFrame()
|
||||
{
|
||||
using Stream vsource = FetchEmbeddedResource("Dashboard.Drawing.OpenGL.default.vert");
|
||||
using Stream fsource = FetchEmbeddedResource("Dashboard.Drawing.OpenGL.default.frag");
|
||||
int vs = CompileShader(ShaderType.VertexShader, vsource);
|
||||
int fs = CompileShader(ShaderType.FragmentShader, fsource);
|
||||
_program = LinkProgram(vs, fs);
|
||||
GL.DeleteShader(vs);
|
||||
GL.DeleteShader(fs);
|
||||
foreach (ICommandExecutor executor in _executorsList)
|
||||
executor.BeginFrame();
|
||||
}
|
||||
|
||||
public void Draw(DrawQueue drawqueue) => Draw(drawqueue, new RectangleF(new PointF(0f,0f), Context.FramebufferSize));
|
||||
public virtual void Draw(DrawQueue drawQueue, RectangleF bounds)
|
||||
protected virtual void BeginDraw()
|
||||
{
|
||||
foreach (ICommandExecutor executor in _executorsList)
|
||||
executor.BeginDraw();
|
||||
}
|
||||
|
||||
protected virtual void EndDraw()
|
||||
{
|
||||
foreach (ICommandExecutor executor in _executorsList)
|
||||
executor.EndDraw();
|
||||
}
|
||||
|
||||
public virtual void EndFrame()
|
||||
{
|
||||
ResourcePool.Collector.Dispose();
|
||||
TransformStack.Clear();
|
||||
|
||||
foreach (ICommandExecutor executor in _executorsList)
|
||||
executor.EndFrame();
|
||||
}
|
||||
|
||||
private void DisposeInvoker(bool disposing)
|
||||
public void Draw(DrawQueue drawqueue) => Draw(drawqueue, new RectangleF(new PointF(0f,0f), Context.FramebufferSize));
|
||||
|
||||
public virtual void Draw(DrawQueue drawQueue, RectangleF bounds)
|
||||
{
|
||||
BeginDraw();
|
||||
|
||||
foreach (ICommandFrame frame in drawQueue)
|
||||
{
|
||||
if (_executorsMap.TryGetValue(frame.Command.Extension.Name, out ICommandExecutor? executor))
|
||||
executor.ProcessCommand(frame);
|
||||
}
|
||||
|
||||
EndDraw();
|
||||
}
|
||||
|
||||
private void DisposeInvoker(bool safeExit, bool disposing)
|
||||
{
|
||||
if (!IsDisposed)
|
||||
return;
|
||||
@ -68,67 +151,28 @@ namespace Dashboard.Drawing.OpenGL
|
||||
if (disposing)
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
Dispose(disposing);
|
||||
Dispose(safeExit, disposing);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
protected virtual void Dispose(bool safeExit, bool disposing)
|
||||
{
|
||||
ContextCollector.Global.DeleteProgram(_program);
|
||||
}
|
||||
|
||||
public void Dispose() => DisposeInvoker(true);
|
||||
|
||||
private static int CompileShader(ShaderType type, string source)
|
||||
if (disposing)
|
||||
{
|
||||
int shader = GL.CreateShader(type);
|
||||
|
||||
GL.ShaderSource(shader, source);
|
||||
GL.CompileShader(shader);
|
||||
|
||||
int compileStatus = 0;
|
||||
GL.GetShaderi(shader, ShaderParameterName.CompileStatus, out compileStatus);
|
||||
|
||||
if (compileStatus == 0)
|
||||
foreach (ICommandExecutor executor in _executorsList)
|
||||
{
|
||||
GL.GetShaderInfoLog(shader, out string log);
|
||||
GL.DeleteShader(shader);
|
||||
throw new Exception($"{type} Shader compilation failed: " + log);
|
||||
if (executor is IGLDisposable glDisposable)
|
||||
glDisposable.Dispose(safeExit);
|
||||
else if (executor is IDisposable disposable)
|
||||
disposable.Dispose();
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
private static int CompileShader(ShaderType type, Stream stream)
|
||||
{
|
||||
using StreamReader reader = new StreamReader(stream, leaveOpen: true);
|
||||
|
||||
return CompileShader(type, reader.ReadToEnd());
|
||||
}
|
||||
|
||||
private static int LinkProgram(int s1, int s2)
|
||||
{
|
||||
int program = GL.CreateProgram();
|
||||
|
||||
GL.AttachShader(program, s1);
|
||||
GL.AttachShader(program, s2);
|
||||
|
||||
GL.LinkProgram(program);
|
||||
|
||||
int linkStatus = 0;
|
||||
GL.GetProgrami(program, ProgramProperty.LinkStatus, out linkStatus);
|
||||
if (linkStatus == 0)
|
||||
{
|
||||
GL.GetProgramInfoLog(program, out string log);
|
||||
GL.DeleteProgram(program);
|
||||
throw new Exception("Shader program linking failed: " + log);
|
||||
}
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
private static Stream FetchEmbeddedResource(string name)
|
||||
{
|
||||
return typeof(ContextExecutor).Assembly.GetManifestResourceStream(name)!;
|
||||
if (ResourcePool.DecrementReference())
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() => DisposeInvoker(true, true);
|
||||
|
||||
public void Dispose(bool safeExit) => DisposeInvoker(safeExit, true);
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="default.frag" />
|
||||
<EmbeddedResource Include="default.frag" />
|
||||
<None Remove="default.vert" />
|
||||
<EmbeddedResource Include="default.vert" />
|
||||
<EmbeddedResource Include="Executors\simple.frag" />
|
||||
<EmbeddedResource Include="Executors\simple.vert" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
227
Dashboard.Drawing.OpenGL/DrawCallRecorder.cs
Normal file
227
Dashboard.Drawing.OpenGL/DrawCallRecorder.cs
Normal file
@ -0,0 +1,227 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using OpenTK.Mathematics;
|
||||
using Vector2 = System.Numerics.Vector2;
|
||||
using Vector3 = System.Numerics.Vector3;
|
||||
|
||||
namespace Dashboard.Drawing.OpenGL
|
||||
{
|
||||
public class DrawCallRecorder : IGLDisposable, IInitializer
|
||||
{
|
||||
private int _vao = 0;
|
||||
private int _vbo = 0;
|
||||
private readonly List<DrawVertex> _vertices = new List<DrawVertex>();
|
||||
private readonly List<DrawCall> _calls = new List<DrawCall>();
|
||||
|
||||
private int _start = 0;
|
||||
private int _count = 0;
|
||||
private int _primitives = 0;
|
||||
private Vector3 _charCoords;
|
||||
private int _cmdIndex;
|
||||
private int _texture0, _texture1, _texture2, _texture3;
|
||||
private TextureTarget _target0, _target1, _target2, _target3;
|
||||
private Matrix4 _transforms = Matrix4.Identity;
|
||||
|
||||
public int CommandModulus = 64;
|
||||
public int CommandBuffer = 0;
|
||||
public int CommandSize = 64;
|
||||
|
||||
private int CommandByteSize => CommandModulus * CommandSize;
|
||||
|
||||
public int TransformsLocation { get; set; }
|
||||
|
||||
public void Transforms(in Matrix4 transforms)
|
||||
{
|
||||
_transforms = transforms;
|
||||
}
|
||||
|
||||
public void Begin(PrimitiveType type)
|
||||
{
|
||||
if (_primitives != 0)
|
||||
throw new InvalidOperationException("Attempt to begin new draw call before finishing previous one.");
|
||||
|
||||
_primitives = (int)type;
|
||||
_start = _vertices.Count;
|
||||
_count = 0;
|
||||
}
|
||||
|
||||
public void TexCoords2(Vector2 texCoords)
|
||||
{
|
||||
_charCoords = new Vector3(texCoords, 0);
|
||||
}
|
||||
|
||||
public void CharCoords(Vector3 charCoords)
|
||||
{
|
||||
_charCoords = charCoords;
|
||||
}
|
||||
|
||||
public void CommandIndex(int index)
|
||||
{
|
||||
_cmdIndex = index;
|
||||
}
|
||||
|
||||
public void Vertex3(Vector3 vertex)
|
||||
{
|
||||
_vertices.Add(new DrawVertex()
|
||||
{
|
||||
Position = vertex,
|
||||
CharCoords = _charCoords,
|
||||
CmdIndex = _cmdIndex % CommandModulus,
|
||||
});
|
||||
_count++;
|
||||
}
|
||||
|
||||
public void End()
|
||||
{
|
||||
if (_primitives == 0)
|
||||
throw new InvalidOperationException("Attempt to end draw call before starting one.");
|
||||
|
||||
_calls.Add(
|
||||
new DrawCall()
|
||||
{
|
||||
Type = (PrimitiveType)_primitives,
|
||||
Start = _start,
|
||||
Count = _count,
|
||||
CmdIndex = _cmdIndex,
|
||||
Target0 = _target0,
|
||||
Target1 = _target1,
|
||||
Target2 = _target2,
|
||||
Target3 = _target3,
|
||||
Texture0 = _texture0,
|
||||
Texture1 = _texture1,
|
||||
Texture2 = _texture2,
|
||||
Texture3 = _texture3,
|
||||
Transforms = _transforms,
|
||||
});
|
||||
|
||||
_primitives = 0;
|
||||
}
|
||||
|
||||
public void BindTexture(TextureTarget target, int texture) => BindTexture(target, 0, texture);
|
||||
|
||||
public void BindTexture(TextureTarget target, int unit, int texture)
|
||||
{
|
||||
switch (unit)
|
||||
{
|
||||
case 0:
|
||||
_texture0 = 0;
|
||||
_target0 = target;
|
||||
break;
|
||||
case 1:
|
||||
_texture1 = 0;
|
||||
_target1 = target;
|
||||
break;
|
||||
case 2:
|
||||
_texture2 = 0;
|
||||
_target2 = target;
|
||||
break;
|
||||
case 3:
|
||||
_texture3 = 0;
|
||||
_target3 = target;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(unit), "I did not write support for more than 4 textures.");
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawArrays(PrimitiveType type, int first, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
GL.BindVertexArray(_vao);
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo);
|
||||
|
||||
ReadOnlySpan<DrawVertex> vertices = CollectionsMarshal.AsSpan(_vertices);
|
||||
GL.BufferData(BufferTarget.ArrayBuffer, _vertices.Count * Unsafe.SizeOf<DrawVertex>(), vertices, BufferUsage.DynamicDraw);
|
||||
|
||||
foreach (DrawCall call in _calls)
|
||||
{
|
||||
GL.BindBufferRange(BufferTarget.UniformBuffer, 0, CommandBuffer, call.CmdIndex / CommandModulus * CommandByteSize, CommandByteSize);
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
GL.BindTexture(call.Target0, call.Texture0);
|
||||
GL.ActiveTexture(TextureUnit.Texture1);
|
||||
GL.BindTexture(call.Target1, call.Texture1);
|
||||
GL.ActiveTexture(TextureUnit.Texture2);
|
||||
GL.BindTexture(call.Target2, call.Texture2);
|
||||
GL.ActiveTexture(TextureUnit.Texture3);
|
||||
GL.BindTexture(call.Target3, call.Texture3);
|
||||
|
||||
Matrix4 transforms = call.Transforms;
|
||||
GL.UniformMatrix4f(TransformsLocation, 1, true, ref transforms);
|
||||
GL.DrawArrays(call.Type, call.Start, call.Count);
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_vertices.Clear();
|
||||
_calls.Clear();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Dispose(bool safeExit)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsInitialized { get; private set; }
|
||||
public void Initialize()
|
||||
{
|
||||
if (IsInitialized)
|
||||
return;
|
||||
IsInitialized = true;
|
||||
|
||||
_vao = GL.CreateVertexArray();
|
||||
_vbo = GL.CreateBuffer();
|
||||
|
||||
GL.BindVertexArray(_vao);
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo);
|
||||
|
||||
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 32, 0);
|
||||
GL.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, false, 32, 16);
|
||||
GL.VertexAttribIPointer(2, 1, VertexAttribIType.Int, 32, 28);
|
||||
GL.EnableVertexAttribArray(0);
|
||||
GL.EnableVertexAttribArray(1);
|
||||
GL.EnableVertexAttribArray(2);
|
||||
}
|
||||
|
||||
private struct DrawCall
|
||||
{
|
||||
public PrimitiveType Type;
|
||||
public int Start;
|
||||
public int Count;
|
||||
public int CmdIndex;
|
||||
|
||||
public int Texture0;
|
||||
public int Texture1;
|
||||
public int Texture2;
|
||||
public int Texture3;
|
||||
|
||||
public TextureTarget Target0;
|
||||
public TextureTarget Target1;
|
||||
public TextureTarget Target2;
|
||||
public TextureTarget Target3;
|
||||
|
||||
public Matrix4 Transforms;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 32)]
|
||||
private struct DrawVertex
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public Vector3 Position;
|
||||
[FieldOffset(16)]
|
||||
public Vector3 CharCoords;
|
||||
[FieldOffset(28)]
|
||||
public int CmdIndex;
|
||||
}
|
||||
}
|
||||
}
|
332
Dashboard.Drawing.OpenGL/Executors/BaseCommandExecutor.cs
Normal file
332
Dashboard.Drawing.OpenGL/Executors/BaseCommandExecutor.cs
Normal file
@ -0,0 +1,332 @@
|
||||
using System.Drawing;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using System.Numerics;
|
||||
using OTK = OpenTK.Mathematics;
|
||||
|
||||
namespace Dashboard.Drawing.OpenGL.Executors
|
||||
{
|
||||
public class BaseCommandExecutor : IInitializer, ICommandExecutor
|
||||
{
|
||||
private int _program = 0;
|
||||
private readonly MappableBumpAllocator<CommandInfo> _commands = new MappableBumpAllocator<CommandInfo>();
|
||||
private readonly DrawCallRecorder _calls = new DrawCallRecorder();
|
||||
|
||||
public bool IsInitialized { get; private set; }
|
||||
public IEnumerable<string> Extensions { get; } = new[] { "DB_base" };
|
||||
public IContextExecutor Executor { get; private set; } = null!;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
if (IsInitialized) return;
|
||||
|
||||
if (Executor == null)
|
||||
throw new Exception("Executor has not been set.");
|
||||
|
||||
IsInitialized = true;
|
||||
|
||||
LoadShaders();
|
||||
}
|
||||
|
||||
public void SetContextExecutor(IContextExecutor executor)
|
||||
{
|
||||
Executor = executor;
|
||||
}
|
||||
|
||||
public void BeginFrame()
|
||||
{
|
||||
}
|
||||
|
||||
public void BeginDraw()
|
||||
{
|
||||
_commands.Initialize();
|
||||
_calls.Initialize();
|
||||
|
||||
Size size = Executor.Context.FramebufferSize;
|
||||
|
||||
Executor.TransformStack.Push(OTK.Matrix4.CreateOrthographicOffCenter(
|
||||
0,
|
||||
size.Width,
|
||||
size.Height,
|
||||
0,
|
||||
1,
|
||||
-1));
|
||||
|
||||
GL.Viewport(0, 0, size.Width, size.Height);
|
||||
}
|
||||
|
||||
public void EndDraw()
|
||||
{
|
||||
_commands.Unmap();
|
||||
GL.UseProgram(_program);
|
||||
_calls.CommandBuffer = _commands.Handle;
|
||||
_calls.Execute();
|
||||
}
|
||||
|
||||
public void EndFrame()
|
||||
{
|
||||
_commands.Clear();
|
||||
_calls.Clear();
|
||||
}
|
||||
|
||||
public void ProcessCommand(ICommandFrame frame)
|
||||
{
|
||||
switch (frame.Command.Name)
|
||||
{
|
||||
case "Point":
|
||||
DrawBasePoint(frame);
|
||||
break;
|
||||
case "Line":
|
||||
DrawBaseLine(frame);
|
||||
break;
|
||||
case "RectF":
|
||||
case "RectS":
|
||||
case "RectFS":
|
||||
DrawRect(frame);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawBasePoint(ICommandFrame frame)
|
||||
{
|
||||
ref CommandInfo info = ref _commands.Take(out int index);
|
||||
|
||||
PointCommandArgs args = frame.GetParameter<PointCommandArgs>();
|
||||
|
||||
info = new CommandInfo()
|
||||
{
|
||||
Type = SimpleDrawCommand.Point,
|
||||
Arg0 = args.Size,
|
||||
};
|
||||
|
||||
SetCommandCommonBrush(ref info, args.Brush, args.Brush);
|
||||
|
||||
_calls.Transforms(Executor.TransformStack.Top);
|
||||
_calls.Begin(PrimitiveType.Triangles);
|
||||
_calls.CommandIndex(index);
|
||||
DrawPoint(args.Position, args.Depth, args.Size);
|
||||
_calls.End();
|
||||
}
|
||||
|
||||
private void DrawPoint(Vector2 position, float depth, float diameter)
|
||||
{
|
||||
// Draw a point as a isocles triangle.
|
||||
const float adjust = 1.1f;
|
||||
const float cos30 = 0.8660254038f;
|
||||
Vector2 top = adjust * new Vector2(0, -cos30);
|
||||
Vector2 left = adjust * new Vector2(-cos30, 0.5f);
|
||||
Vector2 right = adjust * new Vector2(cos30, 0.5f);
|
||||
|
||||
_calls.TexCoords2(top);
|
||||
_calls.Vertex3(new Vector3(position + top * diameter, depth));
|
||||
_calls.TexCoords2(left);
|
||||
_calls.Vertex3(new Vector3(position + left * diameter, depth));
|
||||
_calls.TexCoords2(right);
|
||||
_calls.Vertex3(new Vector3(position + right * diameter, depth));
|
||||
}
|
||||
|
||||
private void DrawBaseLine(ICommandFrame frame)
|
||||
{
|
||||
ref CommandInfo info = ref _commands.Take(out int index);
|
||||
|
||||
LineCommandArgs args = frame.GetParameter<LineCommandArgs>();
|
||||
|
||||
info = new CommandInfo()
|
||||
{
|
||||
Type = SimpleDrawCommand.Line,
|
||||
Arg0 = 0.5f * args.Size / (args.End - args.Start).Length(),
|
||||
};
|
||||
|
||||
SetCommandCommonBrush(ref info, args.Brush, args.Brush);
|
||||
|
||||
_calls.Transforms(Executor.TransformStack.Top);
|
||||
_calls.Begin(PrimitiveType.Triangles);
|
||||
|
||||
_calls.CommandIndex(index);
|
||||
|
||||
DrawLine(args.Start, args.End, args.Depth, args.Size);
|
||||
|
||||
_calls.End();
|
||||
}
|
||||
|
||||
private void DrawLine(Vector2 start, Vector2 end, float depth, float width)
|
||||
{
|
||||
float radius = 0.5f * width;
|
||||
Vector2 segment = end - start;
|
||||
float length = segment.Length();
|
||||
float ratio = radius / length;
|
||||
Vector2 n = ratio * segment;
|
||||
Vector2 t = new Vector2(-n.Y, n.X);
|
||||
|
||||
Vector2 t00 = new Vector2(-ratio, -ratio);
|
||||
Vector2 t10 = new Vector2(1+ratio, -ratio);
|
||||
Vector2 t01 = new Vector2(-ratio, +ratio);
|
||||
Vector2 t11 = new Vector2(1+ratio, +ratio);
|
||||
|
||||
Vector3 x00 = new Vector3(start - n - t, depth);
|
||||
Vector3 x10 = new Vector3(end + n - t, depth);
|
||||
Vector3 x01 = new Vector3(start - n + t, depth);
|
||||
Vector3 x11 = new Vector3(end + n + t, depth);
|
||||
|
||||
_calls.TexCoords2(t00);
|
||||
_calls.Vertex3(x00);
|
||||
_calls.TexCoords2(t01);
|
||||
_calls.Vertex3(x01);
|
||||
_calls.TexCoords2(t11);
|
||||
_calls.Vertex3(x11);
|
||||
|
||||
_calls.TexCoords2(t00);
|
||||
_calls.Vertex3(x00);
|
||||
_calls.TexCoords2(t11);
|
||||
_calls.Vertex3(x11);
|
||||
_calls.TexCoords2(t10);
|
||||
_calls.Vertex3(x10);
|
||||
}
|
||||
|
||||
private void DrawRect(ICommandFrame frame)
|
||||
{
|
||||
ref CommandInfo info = ref _commands.Take(out int index);
|
||||
|
||||
RectCommandArgs args = frame.GetParameter<RectCommandArgs>();
|
||||
|
||||
Vector2 size = Vector2.Abs(args.End - args.Start);
|
||||
float aspect = size.X / size.Y;
|
||||
float border = args.StrikeSize;
|
||||
float normRad = args.StrikeSize / size.Y;
|
||||
float wideRad = aspect * normRad;
|
||||
|
||||
int flags = 0;
|
||||
|
||||
switch (frame.Command.Name)
|
||||
{
|
||||
case "RectF":
|
||||
flags |= 1;
|
||||
break;
|
||||
case "RectS":
|
||||
flags |= 2;
|
||||
break;
|
||||
case "RectFS":
|
||||
flags |= 3;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (args.BorderKind)
|
||||
{
|
||||
case BorderKind.Inset:
|
||||
flags |= 2 << 2;
|
||||
break;
|
||||
case BorderKind.Outset:
|
||||
flags |= 1 << 2;
|
||||
break;
|
||||
}
|
||||
|
||||
info = new CommandInfo()
|
||||
{
|
||||
Type = SimpleDrawCommand.Rect,
|
||||
Flags = flags,
|
||||
Arg0 = aspect,
|
||||
Arg1 = normRad,
|
||||
};
|
||||
|
||||
SetCommandCommonBrush(ref info, args.FillBrush, args.StrikeBrush);
|
||||
|
||||
_calls.Transforms(Executor.TransformStack.Top);
|
||||
_calls.Begin(PrimitiveType.Triangles);
|
||||
|
||||
_calls.CommandIndex(index);
|
||||
|
||||
Vector2 t00 = new Vector2(-wideRad, -normRad);
|
||||
Vector2 t10 = new Vector2(1+wideRad, -normRad);
|
||||
Vector2 t01 = new Vector2(-wideRad, 1+normRad);
|
||||
Vector2 t11 = new Vector2(1+wideRad, 1+normRad);
|
||||
|
||||
Vector3 x00 = new Vector3(args.Start.X - border, args.Start.Y - border, args.Depth);
|
||||
Vector3 x10 = new Vector3(args.End.X + border, args.Start.Y - border, args.Depth);
|
||||
Vector3 x01 = new Vector3(args.Start.X - border, args.End.Y + border, args.Depth);
|
||||
Vector3 x11 = new Vector3(args.End.X + border, args.End.Y + border, args.Depth);
|
||||
|
||||
_calls.TexCoords2(t00);
|
||||
_calls.Vertex3(x00);
|
||||
_calls.TexCoords2(t01);
|
||||
_calls.Vertex3(x01);
|
||||
_calls.TexCoords2(t11);
|
||||
_calls.Vertex3(x11);
|
||||
|
||||
_calls.TexCoords2(t00);
|
||||
_calls.Vertex3(x00);
|
||||
_calls.TexCoords2(t11);
|
||||
_calls.Vertex3(x11);
|
||||
_calls.TexCoords2(t10);
|
||||
_calls.Vertex3(x10);
|
||||
|
||||
_calls.End();
|
||||
}
|
||||
|
||||
protected void SetCommandCommonBrush(ref CommandInfo info, IBrush? fill, IBrush? border)
|
||||
{
|
||||
switch (fill?.Kind.Name)
|
||||
{
|
||||
case "DB_Brush_solid":
|
||||
SolidBrush solid = (SolidBrush)fill;
|
||||
Vector4 color = new Vector4(solid.Color.R/255f, solid.Color.G/255f, solid.Color.B/255f, solid.Color.A/255f);
|
||||
info.FgColor = color;
|
||||
break;
|
||||
case "DB_Brush_gradient":
|
||||
GradientBrush gradient = (GradientBrush)fill;
|
||||
GradientUniformBuffer gradients = Executor.ResourcePool.GetResourceManager<GradientUniformBuffer>();
|
||||
gradients.Initialize();
|
||||
GradientUniformBuffer.Entry entry = gradients.InternGradient(gradient.Gradient);
|
||||
info.FgGradientIndex = entry.Offset;
|
||||
info.FgGradientCount = entry.Count;
|
||||
break;
|
||||
case null:
|
||||
// Craete a magenta brush for this.
|
||||
info.FgColor = new Vector4(1, 0, 1, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (border?.Kind.Name)
|
||||
{
|
||||
case "DB_Brush_solid":
|
||||
SolidBrush solid = (SolidBrush)border;
|
||||
Vector4 color = new Vector4(solid.Color.R/255f, solid.Color.G/255f, solid.Color.B/255f, solid.Color.A/255f);
|
||||
info.BgColor = color;
|
||||
break;
|
||||
case "DB_Brush_gradient":
|
||||
GradientBrush gradient = (GradientBrush)border;
|
||||
GradientUniformBuffer gradients = Executor.ResourcePool.GetResourceManager<GradientUniformBuffer>();
|
||||
gradients.Initialize();
|
||||
GradientUniformBuffer.Entry entry = gradients.InternGradient(gradient.Gradient);
|
||||
info.BgGradientIndex = entry.Offset;
|
||||
info.BgGradientCount = entry.Count;
|
||||
break;
|
||||
case null:
|
||||
// Craete a magenta brush for this.
|
||||
info.BgColor = new Vector4(1, 0, 1, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadShaders()
|
||||
{
|
||||
using Stream vsource = FetchEmbeddedResource("Dashboard.Drawing.OpenGL.Executors.simple.vert");
|
||||
using Stream fsource = FetchEmbeddedResource("Dashboard.Drawing.OpenGL.Executors.simple.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",
|
||||
"a_iCmdIndex",
|
||||
});
|
||||
GL.DeleteShader(vs);
|
||||
GL.DeleteShader(fs);
|
||||
|
||||
GL.UniformBlockBinding(_program, GL.GetUniformBlockIndex(_program, "CommandBlock"), 0);
|
||||
}
|
||||
|
||||
private static Stream FetchEmbeddedResource(string name)
|
||||
{
|
||||
return typeof(BaseCommandExecutor).Assembly.GetManifestResourceStream(name)!;
|
||||
}
|
||||
}
|
||||
}
|
224
Dashboard.Drawing.OpenGL/Executors/simple.frag
Normal file
224
Dashboard.Drawing.OpenGL/Executors/simple.frag
Normal file
@ -0,0 +1,224 @@
|
||||
#version 140
|
||||
|
||||
#define DB_GRADIENT_MAX 16
|
||||
#define DB_COMMAND_MAX 64
|
||||
|
||||
#define CMD_POINT 1
|
||||
#define CMD_LINE 2
|
||||
#define CMD_RECT 3
|
||||
|
||||
#define STRIKE_CENTER 0
|
||||
#define STRIKE_OUTSET 1
|
||||
#define STRIKE_INSET 2
|
||||
|
||||
in vec3 v_v3Position;
|
||||
in vec2 v_v2TexCoords;
|
||||
flat in int v_iCmdIndex;
|
||||
|
||||
out vec4 f_Color;
|
||||
|
||||
uniform sampler2D txForeground;
|
||||
uniform sampler2D txBackground;
|
||||
|
||||
struct Gradient_t {
|
||||
float fPosition;
|
||||
float pad0;
|
||||
float pad1;
|
||||
float pad2;
|
||||
vec4 v4Color;
|
||||
};
|
||||
|
||||
uniform GradientBlock
|
||||
{
|
||||
Gradient_t vstGradientStops[DB_GRADIENT_MAX];
|
||||
};
|
||||
|
||||
vec4 getGradientColor(float position, int index, int count)
|
||||
{
|
||||
position = clamp(position, 0, 1);
|
||||
|
||||
int i0 = 0;
|
||||
float p0 = vstGradientStops[index + i0].fPosition;
|
||||
|
||||
int i1 = count - 1;
|
||||
float p1 = vstGradientStops[index + i1].fPosition;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
float px = vstGradientStops[index + i].fPosition;
|
||||
|
||||
if (px > p0 && px <= position)
|
||||
{
|
||||
p0 = px;
|
||||
i0 = i;
|
||||
}
|
||||
|
||||
if (px < p1 && px >= position)
|
||||
{
|
||||
p1 = px;
|
||||
i1 = i;
|
||||
}
|
||||
}
|
||||
|
||||
vec4 c0 = vstGradientStops[index + i0].v4Color;
|
||||
vec4 c1 = vstGradientStops[index + i1].v4Color;
|
||||
|
||||
float l = p1 - p0;
|
||||
float w = (l > 0) ? (position - p0) / (p1 - p0) : 0;
|
||||
|
||||
return mix(c0, c1, w);
|
||||
}
|
||||
|
||||
struct CommandInfo_t {
|
||||
int iCommand;
|
||||
int iFlags;
|
||||
float fArg0;
|
||||
float fArg1;
|
||||
|
||||
int iFgGradientIndex;
|
||||
int iFgGradientCount;
|
||||
int iBgGradientIndex;
|
||||
int iBgGradientCount;
|
||||
|
||||
vec4 v4FgColor;
|
||||
vec4 v4BgColor;
|
||||
};
|
||||
|
||||
uniform CommandBlock
|
||||
{
|
||||
CommandInfo_t vstCommandInfo[DB_COMMAND_MAX];
|
||||
};
|
||||
|
||||
CommandInfo_t getCommandInfo()
|
||||
{
|
||||
return vstCommandInfo[v_iCmdIndex];
|
||||
}
|
||||
|
||||
vec4 fgColor()
|
||||
{
|
||||
return getCommandInfo().v4FgColor;
|
||||
}
|
||||
|
||||
vec4 bgColor()
|
||||
{
|
||||
return getCommandInfo().v4BgColor;
|
||||
}
|
||||
|
||||
void Point(void)
|
||||
{
|
||||
vec4 fg = fgColor();
|
||||
|
||||
if (dot(v_v2TexCoords, v_v2TexCoords) <= 0.25)
|
||||
f_Color = fg;
|
||||
else
|
||||
discard;
|
||||
}
|
||||
|
||||
#define LINE_NORMALIZED_RADIUS(cmd) cmd.fArg0
|
||||
void Line(void)
|
||||
{
|
||||
vec4 fg = fgColor();
|
||||
CommandInfo_t cmd = getCommandInfo();
|
||||
|
||||
float t = clamp(v_v2TexCoords.x, 0, 1);
|
||||
vec2 dv = v_v2TexCoords - vec2(t, 0);
|
||||
float d = dot(dv, dv);
|
||||
|
||||
float lim = LINE_NORMALIZED_RADIUS(cmd);
|
||||
lim *= lim;
|
||||
|
||||
if (d <= lim)
|
||||
f_Color = fg;
|
||||
else
|
||||
discard;
|
||||
}
|
||||
|
||||
#define RECT_ASPECT_RATIO(cmd) (cmd.fArg0)
|
||||
#define RECT_BORDER_WIDTH(cmd) (cmd.fArg1)
|
||||
#define RECT_FILL(cmd) ((cmd.iFlags & (1 << 0)) != 0)
|
||||
#define RECT_BORDER(cmd) ((cmd.iFlags & (1 << 1)) != 0)
|
||||
#define RECT_STRIKE_MASK 3
|
||||
#define RECT_STRIKE_SHIFT 2
|
||||
#define RECT_STRIKE_KIND(cmd) ((cmd.iFlags & RECT_STRIKE_MASK) >> RECT_STRIKE_SHIFT)
|
||||
void Rect(void)
|
||||
{
|
||||
vec4 fg = fgColor();
|
||||
vec4 bg = bgColor();
|
||||
|
||||
CommandInfo_t cmd = getCommandInfo();
|
||||
float aspect = RECT_ASPECT_RATIO(cmd);
|
||||
float border = RECT_BORDER_WIDTH(cmd);
|
||||
int strikeKind = RECT_STRIKE_KIND(cmd);
|
||||
|
||||
vec2 p = abs(2*v_v2TexCoords - vec2(1));
|
||||
p.x = p.x/aspect;
|
||||
|
||||
float m0;
|
||||
float m1;
|
||||
if (!RECT_BORDER(cmd))
|
||||
{
|
||||
m0 = 1;
|
||||
m1 = 1;
|
||||
}
|
||||
else if (strikeKind == STRIKE_OUTSET)
|
||||
{
|
||||
m0 = 1;
|
||||
m1 = border;
|
||||
}
|
||||
else if (strikeKind == STRIKE_INSET)
|
||||
{
|
||||
m0 = 1-border;
|
||||
m1 = 1;
|
||||
}
|
||||
else // strikeKind == STRIKE_CENTER
|
||||
{
|
||||
float h = 0.5 * border;
|
||||
m0 = 1-border;
|
||||
m1 = 1+border;
|
||||
}
|
||||
|
||||
if (p.x > m1*aspect || p.y > m1)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
if (RECT_FILL(cmd))
|
||||
{
|
||||
if (p.x <= 1 && p.y <= 1)
|
||||
{
|
||||
f_Color = fg;
|
||||
}
|
||||
}
|
||||
|
||||
if (RECT_BORDER(cmd))
|
||||
{
|
||||
float x = clamp(p.x, aspect*m0, aspect*m1);
|
||||
float y = clamp(p.y, m0, m1);
|
||||
|
||||
if (p.x == x || p.y == y)
|
||||
{
|
||||
f_Color = bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
switch (getCommandInfo().iCommand)
|
||||
{
|
||||
case CMD_POINT:
|
||||
Point();
|
||||
break;
|
||||
case CMD_LINE:
|
||||
Line();
|
||||
break;
|
||||
case CMD_RECT:
|
||||
Rect();
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unimplemented value.
|
||||
f_Color = vec4(1, 0, 1, 1);
|
||||
break;
|
||||
}
|
||||
}
|
@ -2,12 +2,10 @@
|
||||
|
||||
in vec3 a_v3Position;
|
||||
in vec2 a_v2TexCoords;
|
||||
in vec3 a_v3CharCoords;
|
||||
in int a_iCmdIndex;
|
||||
|
||||
out vec3 v_v3Position;
|
||||
out vec2 v_v2TexCoords;
|
||||
out vec3 v_v3CharCoords;
|
||||
flat out int v_iCmdIndex;
|
||||
|
||||
uniform mat4 m4Transforms;
|
||||
@ -19,6 +17,5 @@ void main(void)
|
||||
v_v3Position = position.xyz/position.w;
|
||||
|
||||
v_v2TexCoords = a_v2TexCoords;
|
||||
v_v3CharCoords = a_v3CharCoords;
|
||||
v_iCmdIndex = a_iCmdIndex;
|
||||
}
|
60
Dashboard.Drawing.OpenGL/ShaderUtil.cs
Normal file
60
Dashboard.Drawing.OpenGL/ShaderUtil.cs
Normal file
@ -0,0 +1,60 @@
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
|
||||
namespace Dashboard.Drawing.OpenGL
|
||||
{
|
||||
public static class ShaderUtil
|
||||
{
|
||||
public static int CompileShader(ShaderType type, string source)
|
||||
{
|
||||
int shader = GL.CreateShader(type);
|
||||
|
||||
GL.ShaderSource(shader, source);
|
||||
GL.CompileShader(shader);
|
||||
|
||||
int compileStatus = 0;
|
||||
GL.GetShaderi(shader, ShaderParameterName.CompileStatus, out compileStatus);
|
||||
|
||||
if (compileStatus == 0)
|
||||
{
|
||||
GL.GetShaderInfoLog(shader, out string log);
|
||||
GL.DeleteShader(shader);
|
||||
throw new Exception($"{type} Shader compilation failed: " + log);
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
public static int CompileShader(ShaderType type, Stream stream)
|
||||
{
|
||||
using StreamReader reader = new StreamReader(stream, leaveOpen: true);
|
||||
|
||||
return CompileShader(type, reader.ReadToEnd());
|
||||
}
|
||||
|
||||
public static int LinkProgram(int s1, int s2, IReadOnlyList<string>? attribLocations = null)
|
||||
{
|
||||
int program = GL.CreateProgram();
|
||||
|
||||
GL.AttachShader(program, s1);
|
||||
GL.AttachShader(program, s2);
|
||||
|
||||
for (int i = 0; i < attribLocations?.Count; i++)
|
||||
{
|
||||
GL.BindAttribLocation(program, (uint)i, attribLocations[i]);
|
||||
}
|
||||
|
||||
GL.LinkProgram(program);
|
||||
|
||||
int linkStatus = 0;
|
||||
GL.GetProgrami(program, ProgramProperty.LinkStatus, out linkStatus);
|
||||
if (linkStatus == 0)
|
||||
{
|
||||
GL.GetProgramInfoLog(program, out string log);
|
||||
GL.DeleteProgram(program);
|
||||
throw new Exception("Shader program linking failed: " + log);
|
||||
}
|
||||
|
||||
return program;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
#version 140
|
||||
|
||||
#define DB_GRADIENT_MAX 16
|
||||
#define DB_COMMAND_MAX 64
|
||||
|
||||
#define CMD_POINT 1
|
||||
#define CMD_LINE 2
|
||||
#define CMD_RECT 3
|
||||
#define CMD_TEXT 4
|
||||
|
||||
#define STRIKE_INSET -1
|
||||
#define STRIKE_CENTER 0
|
||||
#define STRIKE_OUTSET 1
|
||||
|
||||
in vec3 v_v3Position;
|
||||
in vec2 v_v2TexCoords;
|
||||
in int v_iCmdIndex;
|
||||
|
||||
out vec4 f_Color;
|
||||
|
||||
uniform sampler2D txForeground;
|
||||
uniform sampler2D txBackground;
|
||||
uniform sampler2DArray txCharacters;
|
||||
|
||||
struct Gradient_t {
|
||||
float fPosition;
|
||||
float pad0;
|
||||
float pad1;
|
||||
float pad2;
|
||||
vec4 v4Color;
|
||||
};
|
||||
|
||||
uniform GradientBlock
|
||||
{
|
||||
Gradient_t vstGradientStops[DB_GRADIENT_MAX];
|
||||
};
|
||||
|
||||
vec4 getGradientColor(float position, int index, int count)
|
||||
{
|
||||
position = clamp(position, 0, 1);
|
||||
|
||||
int i0 = 0;
|
||||
float p0 = vstGradientStops[index + i0].fPosition;
|
||||
|
||||
int i1 = count - 1;
|
||||
float p1 = vstGradientStops[index + i1].fPosition;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
float px = vstGradientStops[index + i].fPosition;
|
||||
|
||||
if (px > p0 && px <= position)
|
||||
{
|
||||
p0 = px;
|
||||
i0 = i;
|
||||
}
|
||||
|
||||
if (px < p1 && px >= position)
|
||||
{
|
||||
p1 = px;
|
||||
i1 = i;
|
||||
}
|
||||
}
|
||||
|
||||
vec4 c0 = vstGradientStops[index + i0].v4Color;
|
||||
vec4 c1 = vstGradientStops[index + i1].v4Color;
|
||||
|
||||
float l = p1 - p0;
|
||||
float w = (l > 0) ? (position - p0) / (p1 - p0) : 0;
|
||||
|
||||
return mix(c0, c1, w);
|
||||
}
|
||||
|
||||
struct CommandCommon {
|
||||
int iCommand;
|
||||
int iStrikeKind;
|
||||
float fBorderRadius;
|
||||
int _padding;
|
||||
|
||||
int iFgGradientIndex;
|
||||
int iFgGradientCount;
|
||||
int iBgGradientIndex;
|
||||
int iBgGradientCount;
|
||||
|
||||
vec4 v4FillColor;
|
||||
vec4 v4BorderColor;
|
||||
};
|
||||
|
||||
uniform CommandBlock
|
||||
{
|
||||
CommandCommon vstCommands[DB_COMMAND_MAX];
|
||||
};
|
||||
|
||||
void main(void)
|
||||
{
|
||||
|
||||
}
|
@ -102,7 +102,7 @@ namespace Dashboard.Drawing
|
||||
Vector2 min = Vector2.Min(start, end);
|
||||
Vector2 max = Vector2.Max(start, end);
|
||||
controller.EnsureBounds(new Box2d(min, max), depth);
|
||||
controller.Write(DbBaseCommands.Instance.DrawRectF, new RectCommandArgs(start, end, depth, strikeBrush, strikeSize, kind));
|
||||
controller.Write(DbBaseCommands.Instance.DrawRectS, new RectCommandArgs(start, end, depth, strikeBrush, strikeSize, kind));
|
||||
}
|
||||
|
||||
public static void Rect(this DrawQueue queue, Vector2 start, Vector2 end, float depth, IBrush fillBrush, IBrush strikeBrush,
|
||||
@ -112,7 +112,7 @@ namespace Dashboard.Drawing
|
||||
Vector2 min = Vector2.Min(start, end);
|
||||
Vector2 max = Vector2.Max(start, end);
|
||||
controller.EnsureBounds(new Box2d(min, max), depth);
|
||||
controller.Write(DbBaseCommands.Instance.DrawRectF, new RectCommandArgs(start, end, depth, fillBrush, strikeBrush, strikeSize, kind));
|
||||
controller.Write(DbBaseCommands.Instance.DrawRectFS, new RectCommandArgs(start, end, depth, fillBrush, strikeBrush, strikeSize, kind));
|
||||
}
|
||||
|
||||
public static void Text(this DrawQueue queue, Vector3 position, IBrush brush, string text, IFont font,
|
||||
|
@ -6,11 +6,12 @@ using OpenTK.Platform;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using OpenTK.Mathematics;
|
||||
using TK = OpenTK.Platform.Toolkit;
|
||||
using Vector3 = System.Numerics.Vector3;
|
||||
using sys = System.Numerics;
|
||||
using otk = OpenTK.Mathematics;
|
||||
|
||||
TK.Init(new ToolkitOptions()
|
||||
{
|
||||
ApplicationName = "Dashboard Test Application",
|
||||
ApplicationName = "Paper Punch Out!",
|
||||
Windows = new ToolkitOptions.WindowsOptions()
|
||||
{
|
||||
EnableVisualStyles = true,
|
||||
@ -32,13 +33,15 @@ WindowHandle wnd = TK.Window.Create(new OpenGLGraphicsApiHints()
|
||||
GreenColorBits = 8,
|
||||
BlueColorBits = 8,
|
||||
AlphaColorBits = 8,
|
||||
Multisamples = 0,
|
||||
|
||||
SupportTransparentFramebufferX11 = true,
|
||||
});
|
||||
TK.Window.SetTitle(wnd, "Dashboard Test Application");
|
||||
TK.Window.SetTitle(wnd, "Paper Punch Out!");
|
||||
TK.Window.SetMinClientSize(wnd, 300, 200);
|
||||
TK.Window.SetClientSize(wnd, new Vector2i(320, 240));
|
||||
TK.Window.SetBorderStyle(wnd, WindowBorderStyle.ResizableBorder);
|
||||
TK.Window.SetTransparencyMode(wnd, WindowTransparencyMode.TransparentFramebuffer, 0.1f);
|
||||
|
||||
OpenGLContextHandle context = TK.OpenGL.CreateFromWindow(wnd);
|
||||
|
||||
@ -48,8 +51,8 @@ TK.OpenGL.SetSwapInterval(1);
|
||||
GLLoader.LoadBindings(new Pal2BindingsContext(TK.OpenGL, context));
|
||||
|
||||
DrawQueue queue = new DrawQueue();
|
||||
SolidBrush fg = new SolidBrush(Color.Black);
|
||||
SolidBrush bg = new SolidBrush(Color.White);
|
||||
SolidBrush fg = new SolidBrush(Color.FromArgb(0, 0, 0, 0));
|
||||
SolidBrush bg = new SolidBrush(Color.Black);
|
||||
bool shouldExit = false;
|
||||
|
||||
GLEngine engine = new GLEngine();
|
||||
@ -58,6 +61,8 @@ engine.Initialize();
|
||||
GlContext dbGlContext = new GlContext(wnd, context);
|
||||
ContextExecutor executor = engine.GetExecutor(dbGlContext);
|
||||
|
||||
Vector2 mousePos = Vector2.Zero;
|
||||
Random r = new Random();
|
||||
EventQueue.EventRaised += (handle, type, eventArgs) =>
|
||||
{
|
||||
if (handle != wnd)
|
||||
@ -68,25 +73,49 @@ EventQueue.EventRaised += (handle, type, eventArgs) =>
|
||||
case PlatformEventType.Close:
|
||||
shouldExit = true;
|
||||
break;
|
||||
case PlatformEventType.MouseMove:
|
||||
mousePos = ((MouseMoveEventArgs)eventArgs).ClientPosition;
|
||||
break;
|
||||
case PlatformEventType.MouseUp:
|
||||
MouseButtonUpEventArgs mouseUp = (MouseButtonUpEventArgs)eventArgs;
|
||||
if (mouseUp.Button == MouseButton.Button1)
|
||||
{
|
||||
SolidBrush brush = new SolidBrush(Color.FromArgb(r.Next(256), r.Next(256), r.Next(256), 0));
|
||||
queue.Point(new sys::Vector2(mousePos.X, mousePos.Y), 0f, 24f, brush);
|
||||
}
|
||||
break;
|
||||
case PlatformEventType.KeyDown:
|
||||
KeyDownEventArgs keyDown = (KeyDownEventArgs)eventArgs;
|
||||
if (keyDown.Key == Key.Escape || keyDown.Key == Key.Delete || keyDown.Key == Key.Backspace)
|
||||
queue.Clear();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
TK.Window.SetMode(wnd, WindowMode.Normal);
|
||||
|
||||
List<Vector3> points = new List<Vector3>();
|
||||
|
||||
queue.Line(new sys.Vector2(64, 256), new sys.Vector2(64+256, 256), 0, 64f, fg);
|
||||
queue.Rect(new sys.Vector2(16, 16), new sys.Vector2(96, 96), 0, fg, bg, 8f);
|
||||
|
||||
while (!shouldExit)
|
||||
{
|
||||
TK.Window.ProcessEvents(true);
|
||||
|
||||
TK.Window.GetFramebufferSize(wnd, out Vector2i framebufferSize);
|
||||
executor.BeginFrame();
|
||||
|
||||
queue.Clear();
|
||||
queue.Point(Vector3.Zero, 2f, fg);
|
||||
queue.Line(Vector3.Zero, Vector3.One * 2, 2f, bg);
|
||||
queue.Rect(Vector3.UnitX, 2 * Vector3.UnitX + Vector3.UnitY, fg, bg, 2f);
|
||||
// queue.Line(Vector3.Zero, new Vector3(System.Numerics.Vector2.One * 256f, 0), 4f, bg);
|
||||
// queue.Rect(Vector3.UnitX, 2 * Vector3.UnitX + Vector3.UnitY, fg, bg, 2f);
|
||||
|
||||
GL.Viewport(0, 0, framebufferSize.X, framebufferSize.Y);
|
||||
GL.ClearColor(0.3f, 0.3f, 0.3f, 1.0f);
|
||||
GL.ClearColor(0.9f, 0.9f, 0.7f, 1.0f);
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
|
||||
GL.Disable(EnableCap.DepthTest);
|
||||
// GL.Enable(EnableCap.Blend);
|
||||
// GL.BlendFuncSeparate(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha, BlendingFactor.One, BlendingFactor.Zero);
|
||||
GL.ColorMask(true, true, true, true);
|
||||
|
||||
executor.Draw(queue);
|
||||
executor.EndFrame();
|
||||
|
Loading…
Reference in New Issue
Block a user