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 _transforms = new Stack(); private readonly Stack _clipRegions = new Stack(); private readonly Stack _scissorRegions = new Stack(); private int _z = 0; 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); } public int IncrementZ() { return ++_z; } public int DecrementZ() { return --_z; } } }