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; namespace Dashboard.OpenGL.Drawing { public class DeviceContextBase : IDeviceContextBase { private readonly Stack _transforms = new Stack(); private readonly Stack _clipRegions = new Stack(); private readonly Stack _scissorRegions = new Stack(); 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 RectangleF ClipRegion => _clipRegions.Peek(); public RectangleF 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(); SizeF size = ((GLDeviceContext)Context).GLContext.FramebufferSize; _clipRegions.Push(new RectangleF(0,0, size.Width, size.Height)); SetClip(ClipRegion); } public void PushClip(RectangleF clipRegion) { clipRegion = new RectangleF(ClipRegion.X + clipRegion.X, ClipRegion.Y + clipRegion.Y, Math.Min(ClipRegion.Right - clipRegion.X, clipRegion.Width), Math.Min(ClipRegion.Bottom - clipRegion.Y, clipRegion.Height)); _clipRegions.Push(clipRegion); SetClip(clipRegion); } public void PopClip() { _clipRegions.Pop(); SetClip(ClipRegion); } public void ResetScissor() { GL.Disable(EnableCap.ScissorTest); _scissorRegions.Clear(); SizeF size = ((GLDeviceContext)Context).GLContext.FramebufferSize; _scissorRegions.Push(new RectangleF(0,0, size.Width, size.Height)); } public void PushScissor(RectangleF 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(RectangleF rect) { SizeF size = ((GLDeviceContext)Context).GLContext.FramebufferSize; GL.Viewport( (int)Math.Round(rect.X), (int)Math.Round(size.Height - rect.Y - rect.Height), (int)Math.Round(rect.Width), (int)Math.Round(rect.Height)); } void SetScissor(RectangleF rect) { SizeF size = ((GLDeviceContext)Context).GLContext.FramebufferSize; GL.Scissor( (int)Math.Round(rect.X), (int)Math.Round(size.Height - rect.Y - rect.Height), (int)Math.Round(rect.Width), (int)Math.Round(rect.Height)); } public void ResetTransforms() { SizeF size = ((GLDeviceContext)Context).GLContext.FramebufferSize; Matrix4x4 m = Matrix4x4.CreateOrthographicOffCenterLeftHanded(0, size.Width, size.Height, 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); } } }