Files
Dashboard/Dashboard.OpenGL/Drawing/DeviceContextBase.cs

157 lines
5.0 KiB
C#

using System.Drawing;
using System.Numerics;
using Dashboard.Drawing;
using Dashboard.Pal;
using Dashboard.Windowing;
using OpenTK.Graphics.OpenGL;
using OpenTK.Graphics.Wgl;
using OpenTK.Mathematics;
using ColorBuffer = OpenTK.Graphics.OpenGL.ColorBuffer;
using Vector2 = System.Numerics.Vector2;
namespace Dashboard.OpenGL.Drawing
{
public class DeviceContextBase : IDeviceContextBase
{
private readonly Stack<Matrix4x4> _transforms = new Stack<Matrix4x4>();
private readonly Stack<Box2d> _clipRegions = new Stack<Box2d>();
private readonly Stack<Box2d> _scissorRegions = new Stack<Box2d>();
public DeviceContext Context { get; private set; } = null!;
IContextBase IContextExtensionBase.Context => Context;
public string DriverName => "Dashboard OpenGL Device Context";
public string DriverVendor => "Dashboard";
public Version DriverVersion => new Version(0, 1);
public Box2d ClipRegion => _clipRegions.Peek();
public Box2d ScissorRegion => _scissorRegions.Peek();
public Matrix4x4 Transforms => _transforms.Peek();
public float Scale => ScaleOverride > 0 ? ScaleOverride : (Context.Window as IDpiAwareWindow)?.Scale ?? 1;
public float ScaleOverride { get; set; } = -1f;
public void Dispose()
{
}
public void Require(DeviceContext context)
{
Context = context;
ResetClip();
ResetScissor();
ResetTransforms();
}
void IContextExtensionBase.Require(IContextBase context) => Require((DeviceContext)context);
public void ResetClip()
{
_clipRegions.Clear();
Vector2 size = ((GLDeviceContext)Context).GLContext.FramebufferSize;
_clipRegions.Push(new Box2d(Vector2.Zero, size));
SetClip(ClipRegion);
}
public void PushClip(Box2d clipRegion)
{
clipRegion = new Box2d(ClipRegion.Min.X + clipRegion.Min.X, ClipRegion.Min.Y + clipRegion.Min.Y,
Math.Min(ClipRegion.Max.X, ClipRegion.Min.X + clipRegion.Max.X),
Math.Min(ClipRegion.Max.Y, ClipRegion.Max.Y + clipRegion.Max.Y));
_clipRegions.Push(clipRegion);
SetClip(clipRegion);
}
public void PopClip()
{
_clipRegions.Pop();
SetClip(ClipRegion);
}
public void ResetScissor()
{
GL.Disable(EnableCap.ScissorTest);
_scissorRegions.Clear();
Vector2 size = ((GLDeviceContext)Context).GLContext.FramebufferSize;
_scissorRegions.Push(new Box2d(Vector2.Zero, size));
}
public void PushScissor(Box2d scissorRegion)
{
GL.Enable(EnableCap.ScissorTest);
// scissorRegion = new RectangleF(scissorRegion.X + scissorRegion.X, scissorRegion.Y + scissorRegion.Y,
// Math.Min(ScissorRegion.Right - scissorRegion.X, scissorRegion.Width),
// Math.Min(ScissorRegion.Bottom - scissorRegion.Y, scissorRegion.Height));
_scissorRegions.Push(scissorRegion);
SetScissor(scissorRegion);
}
public void PopScissor()
{
if (_scissorRegions.Count == 1)
GL.Disable(EnableCap.ScissorTest);
_scissorRegions.Pop();
SetScissor(ClipRegion);
}
private void SetClip(Box2d rect)
{
Vector2 size = ((GLDeviceContext)Context).GLContext.FramebufferSize;
GL.Viewport(
(int)Math.Round(rect.Min.X),
(int)Math.Round(size.Y - rect.Min.Y - rect.Size.Y),
(int)Math.Round(rect.Size.X),
(int)Math.Round(rect.Size.Y));
}
void SetScissor(Box2d rect)
{
Vector2 size = ((GLDeviceContext)Context).GLContext.FramebufferSize;
GL.Scissor(
(int)Math.Round(rect.Min.X),
(int)Math.Round(size.Y - rect.Min.Y - rect.Size.Y),
(int)Math.Round(rect.Size.X),
(int)Math.Round(rect.Size.Y));
}
public void ResetTransforms()
{
Vector2 size = ((GLDeviceContext)Context).GLContext.FramebufferSize;
Matrix4x4 m = Matrix4x4.CreateOrthographicOffCenterLeftHanded(0, size.X, size.Y, 0, 1, -1);
_transforms.Clear();
_transforms.Push(m);
}
public void PushTransforms(in Matrix4x4 matrix)
{
Matrix4x4 result = matrix * Transforms;
_transforms.Push(result);
}
public void PopTransforms()
{
_transforms.Pop();
}
public void ClearColor(Color color)
{
GL.ClearColor(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f);
GL.Clear(ClearBufferMask.ColorBufferBit);
}
public void ClearDepth()
{
GL.Clear(ClearBufferMask.DepthBufferBit);
}
}
}