From 2932b3b85e7da41d7d2cc56e5f9d48970e7512d2 Mon Sep 17 00:00:00 2001 From: "H. Utku Maden" Date: Wed, 12 Nov 2025 21:24:25 +0300 Subject: [PATCH] Implement new immediate mode. --- Dashboard.Common/Drawing/IImmediateMode.cs | 15 ++ .../{Pal => Drawing}/ITextureExtension.cs | 3 +- Dashboard.Common/Pal/AppContext.cs | 6 +- Dashboard.Common/Pal/DeviceContext.cs | 7 +- Dashboard.Common/Pal/IContextBase.cs | 2 +- Dashboard.Common/Windowing/IWindow.cs | 3 +- .../Dashboard.Drawing.OpenGL.csproj | 1 - Dashboard.Drawing/DrawBuffer.cs | 26 ++ Dashboard.OpenGL/Dashboard.OpenGL.csproj | 9 + Dashboard.OpenGL/Drawing/ImmediateMode.cs | 229 ++++++++++++++++++ Dashboard.OpenGL/Drawing/immediate.frag | 12 + Dashboard.OpenGL/Drawing/immediate.vert | 18 ++ .../Pal/GLDeviceContext.cs | 2 + .../Pal/GLTextureExtension.cs | 0 Dashboard.OpenTK/PAL2/Pal2AppContext.cs | 10 +- ...penGLDeviceContext.cs => Pal2GLContext.cs} | 18 +- Dashboard.OpenTK/PAL2/PhysicalWindow.cs | 17 +- Dashboard/Controls/Control.cs | 2 +- Dashboard/Controls/Form.cs | 2 - Dashboard/Controls/Label.cs | 3 +- tests/Dashboard.TestApplication/Program.cs | 160 ++++++------ 21 files changed, 427 insertions(+), 118 deletions(-) create mode 100644 Dashboard.Common/Drawing/IImmediateMode.cs rename Dashboard.Common/{Pal => Drawing}/ITextureExtension.cs (97%) create mode 100644 Dashboard.Drawing/DrawBuffer.cs create mode 100644 Dashboard.OpenGL/Drawing/ImmediateMode.cs create mode 100644 Dashboard.OpenGL/Drawing/immediate.frag create mode 100644 Dashboard.OpenGL/Drawing/immediate.vert rename {Dashboard.Drawing.OpenGL => Dashboard.OpenGL}/Pal/GLDeviceContext.cs (98%) rename {Dashboard.Drawing.OpenGL => Dashboard.OpenGL}/Pal/GLTextureExtension.cs (100%) rename Dashboard.OpenTK/PAL2/{OpenGLDeviceContext.cs => Pal2GLContext.cs} (86%) diff --git a/Dashboard.Common/Drawing/IImmediateMode.cs b/Dashboard.Common/Drawing/IImmediateMode.cs new file mode 100644 index 0000000..1db25e3 --- /dev/null +++ b/Dashboard.Common/Drawing/IImmediateMode.cs @@ -0,0 +1,15 @@ +using System.Drawing; +using System.Numerics; +using Dashboard.Pal; + +namespace Dashboard.Drawing +{ + public interface IImmediateMode : IDeviceContextExtension + { + void ClearColor(Color color); + + void Line(Vector2 a, Vector2 b, float width, float depth, Vector4 color); + void Rectangle(Box2d rectangle, float depth, Vector4 color); + void Image(Box2d rectangle, Box2d uv, float depth, ITexture texture); + } +} diff --git a/Dashboard.Common/Pal/ITextureExtension.cs b/Dashboard.Common/Drawing/ITextureExtension.cs similarity index 97% rename from Dashboard.Common/Pal/ITextureExtension.cs rename to Dashboard.Common/Drawing/ITextureExtension.cs index 5432375..91ba007 100644 --- a/Dashboard.Common/Pal/ITextureExtension.cs +++ b/Dashboard.Common/Drawing/ITextureExtension.cs @@ -1,6 +1,7 @@ using System.Drawing; +using Dashboard.Pal; -namespace Dashboard.Pal +namespace Dashboard.Drawing { public interface ITextureExtension : IDeviceContextExtension { diff --git a/Dashboard.Common/Pal/AppContext.cs b/Dashboard.Common/Pal/AppContext.cs index 7adba14..13990e7 100644 --- a/Dashboard.Common/Pal/AppContext.cs +++ b/Dashboard.Common/Pal/AppContext.cs @@ -1,5 +1,6 @@ using Dashboard.Collections; using Dashboard.Windowing; +using BindingFlags = System.Reflection.BindingFlags; namespace Dashboard.Pal { @@ -94,7 +95,7 @@ namespace Dashboard.Pal return _preloadedExtensions.Add(() => new T()); } - public T ExtensionRequire() where T : IAppContextExtension, new() + public T ExtensionRequire() where T : IAppContextExtension { T? extension = default; @@ -112,7 +113,8 @@ namespace Dashboard.Pal } else { - extension = new T(); + extension = (T?)typeof(T).GetConstructor(BindingFlags.Public, [])?.Invoke([]) ?? + throw new Exception("Constructor not found."); } _extensions.Add(extension); diff --git a/Dashboard.Common/Pal/DeviceContext.cs b/Dashboard.Common/Pal/DeviceContext.cs index a15c87f..fcfc1cd 100644 --- a/Dashboard.Common/Pal/DeviceContext.cs +++ b/Dashboard.Common/Pal/DeviceContext.cs @@ -1,4 +1,5 @@ using Dashboard.Collections; +using BindingFlags = System.Reflection.BindingFlags; namespace Dashboard.Pal { @@ -41,7 +42,7 @@ namespace Dashboard.Pal return _preloadedExtensions.Add(() => new T()); } - public T ExtensionRequire() where T : IDeviceContextExtension, new() + public T ExtensionRequire() where T : IDeviceContextExtension { T? extension = default; @@ -59,7 +60,9 @@ namespace Dashboard.Pal } else { - extension = new T(); + extension =(T)( + typeof(T).GetConstructor(BindingFlags.Public, []) ?.Invoke([]) + ?? throw new Exception("Could not find a suitable constructor for the given extension.")); } _extensions.Add(extension); diff --git a/Dashboard.Common/Pal/IContextBase.cs b/Dashboard.Common/Pal/IContextBase.cs index f1a8b01..b9b6c00 100644 --- a/Dashboard.Common/Pal/IContextBase.cs +++ b/Dashboard.Common/Pal/IContextBase.cs @@ -63,7 +63,7 @@ namespace Dashboard.Pal /// /// The extension to require. /// The extension instance. - T ExtensionRequire() where T : TExtension, new(); + T ExtensionRequire() where T : TExtension; } /// diff --git a/Dashboard.Common/Windowing/IWindow.cs b/Dashboard.Common/Windowing/IWindow.cs index 9b56ce2..bf733a7 100644 --- a/Dashboard.Common/Windowing/IWindow.cs +++ b/Dashboard.Common/Windowing/IWindow.cs @@ -1,5 +1,6 @@ using System.Drawing; using Dashboard.Events; +using Dashboard.Pal; namespace Dashboard.Windowing { @@ -59,7 +60,7 @@ namespace Dashboard.Windowing /// /// The device context for this window. /// - IDeviceContext DeviceContext { get; } + DeviceContext DeviceContext { get; } /// /// True if the window is double buffered. diff --git a/Dashboard.Drawing.OpenGL/Dashboard.Drawing.OpenGL.csproj b/Dashboard.Drawing.OpenGL/Dashboard.Drawing.OpenGL.csproj index 22856a6..b521667 100644 --- a/Dashboard.Drawing.OpenGL/Dashboard.Drawing.OpenGL.csproj +++ b/Dashboard.Drawing.OpenGL/Dashboard.Drawing.OpenGL.csproj @@ -9,7 +9,6 @@ - diff --git a/Dashboard.Drawing/DrawBuffer.cs b/Dashboard.Drawing/DrawBuffer.cs new file mode 100644 index 0000000..269733b --- /dev/null +++ b/Dashboard.Drawing/DrawBuffer.cs @@ -0,0 +1,26 @@ +using System.Numerics; + +namespace Dashboard.Drawing +{ + public enum DrawPrimitive + { + Point, + Line, + LineStrip, + Triangle, + TriangleFan, + TriangleStrip + } + + public record struct DrawVertex(Vector3 Position, Vector3 TextureCoordinate, Vector4 Color); + + public record DrawInfo(DrawPrimitive Primitive, int Count) + { + + } + + public class DrawBuffer + { + + } +} diff --git a/Dashboard.OpenGL/Dashboard.OpenGL.csproj b/Dashboard.OpenGL/Dashboard.OpenGL.csproj index 298a8bc..b4b7440 100644 --- a/Dashboard.OpenGL/Dashboard.OpenGL.csproj +++ b/Dashboard.OpenGL/Dashboard.OpenGL.csproj @@ -4,10 +4,19 @@ net8.0 enable enable + true + + + + + + + + diff --git a/Dashboard.OpenGL/Drawing/ImmediateMode.cs b/Dashboard.OpenGL/Drawing/ImmediateMode.cs new file mode 100644 index 0000000..899a7a5 --- /dev/null +++ b/Dashboard.OpenGL/Drawing/ImmediateMode.cs @@ -0,0 +1,229 @@ +using System.Drawing; +using System.Numerics; +using System.Runtime.InteropServices; +using Dashboard.Drawing; +using Dashboard.Drawing.OpenGL.Pal; +using Dashboard.Pal; +using OpenTK.Graphics.OpenGL; + +namespace Dashboard.OpenGL.Drawing +{ + public class ImmediateMode : IImmediateMode + { + public string DriverName => "Dashboard OpenGL Immediate Mode"; + public string DriverVendor => "Dashboard"; + public Version DriverVersion { get; } = new Version(1, 0); + + public DeviceContext Context { get; private set; } = null!; + + private int _program; + private uint _program_apos; + private uint _program_atexcoord; + private uint _program_acolor; + private int _program_transforms; + private int _program_image; + private int _vao; + private int _white; + + public void Dispose() + { + } + + public void Require(DeviceContext context) + { + Context = context; + + _program = GL.CreateProgram(); + + int vs = GL.CreateShader(ShaderType.VertexShader); + + using (StreamReader reader = new StreamReader(GetType().Assembly + .GetManifestResourceStream("Dashboard.OpenGL.Drawing.immediate.vert")!)) + { + GL.ShaderSource(vs, reader.ReadToEnd()); + } + GL.CompileShader(vs); + GL.AttachShader(_program, vs); + + int fs = GL.CreateShader(ShaderType.FragmentShader); + + using (StreamReader reader = new StreamReader(GetType().Assembly + .GetManifestResourceStream("Dashboard.OpenGL.Drawing.immediate.frag")!)) + { + GL.ShaderSource(fs, reader.ReadToEnd()); + } + + GL.CompileShader(fs); + GL.AttachShader(_program, fs); + + GL.LinkProgram(_program); + GL.DeleteShader(vs); GL.DeleteShader(fs); + + _program_apos = (uint)GL.GetAttribLocation(_program, "aPos"); + _program_atexcoord = (uint)GL.GetAttribLocation(_program, "aTexCoords"); + _program_acolor = (uint)GL.GetAttribLocation(_program, "aColor"); + + _program_transforms = GL.GetUniformLocation(_program, "transforms"); + _program_image = GL.GetUniformLocation(_program, "image"); + + GL.GenTexture(out _white); + GL.BindTexture(TextureTarget.Texture2d, _white); + GL.TexImage2D(TextureTarget.Texture2d, 0, InternalFormat.Rgb, 1, 1, 0, OpenTK.Graphics.OpenGL.PixelFormat.Rgb, PixelType.Byte, IntPtr.Zero); + GL.TexParameteri(TextureTarget.Texture2d, TextureParameterName.TextureSwizzleA, (int)All.One); + GL.TexParameteri(TextureTarget.Texture2d, TextureParameterName.TextureSwizzleR, (int)All.One); + GL.TexParameteri(TextureTarget.Texture2d, TextureParameterName.TextureSwizzleG, (int)All.One); + GL.TexParameteri(TextureTarget.Texture2d, TextureParameterName.TextureSwizzleB, (int)All.One); + GL.TexParameteri(TextureTarget.Texture2d, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest); + GL.TexParameteri(TextureTarget.Texture2d, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); + + GL.GenVertexArray(out _vao); + } + + 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 Line(Vector2 a, Vector2 b, float width, float depth, Vector4 color) + { + Vector2 normal = Vector2.Normalize(b - a); + Vector2 tangent = new Vector2(-normal.Y, normal.X) * width; + Span vertices = + [ + new ImmediateVertex(new Vector3(a-tangent, depth), Vector2.Zero, color), + new ImmediateVertex(new Vector3(b-tangent, depth), Vector2.Zero, color), + new ImmediateVertex(new Vector3(b+tangent, depth), Vector2.Zero, color), + new ImmediateVertex(new Vector3(a-tangent, depth), Vector2.Zero, color), + new ImmediateVertex(new Vector3(b+tangent, depth), Vector2.Zero, color), + new ImmediateVertex(new Vector3(a+tangent, depth), Vector2.Zero, color), + ]; + + int buffer = GL.GenBuffer(); + GL.BindBuffer(BufferTarget.ArrayBuffer, buffer); + GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * ImmediateVertex.Size, ref vertices[0], BufferUsage.StreamDraw); + + GL.BindVertexArray(_vao); + GL.VertexAttribPointer(_program_apos, 3, VertexAttribPointerType.Float, false, ImmediateVertex.Size, ImmediateVertex.PosOffset); + GL.EnableVertexAttribArray(_program_apos); + GL.VertexAttribPointer(_program_atexcoord, 2, VertexAttribPointerType.Float, false, ImmediateVertex.Size, ImmediateVertex.TexCoordsOffset); + GL.EnableVertexAttribArray(_program_atexcoord); + GL.VertexAttribPointer(_program_acolor, 4, VertexAttribPointerType.Float, false, ImmediateVertex.Size, ImmediateVertex.ColorOffset); + GL.EnableVertexAttribArray(_program_acolor); + + Size size = ((GLDeviceContext)Context).GLContext.FramebufferSize; + Matrix4x4 view = Matrix4x4.CreateOrthographicOffCenter(0, size.Width, 0, size.Height, 1, -1); + + GL.UseProgram(_program); + + GL.ActiveTexture(TextureUnit.Texture0); + GL.BindTexture(TextureTarget.Texture2d, _white); + + GL.UniformMatrix4f(_program_transforms, 1, true, ref view); + GL.Uniform1i(_program_image, 0); + + GL.DrawArrays(PrimitiveType.Triangles, 0, 6); + + GL.DeleteBuffer(buffer); + } + + public void Rectangle(Box2d rectangle, float depth, Vector4 color) + { + Span vertices = + [ + new ImmediateVertex(new Vector3(rectangle.Min.X, rectangle.Min.Y, depth), Vector2.Zero, color), + new ImmediateVertex(new Vector3(rectangle.Max.X, rectangle.Min.Y, depth), Vector2.Zero, color), + new ImmediateVertex(new Vector3(rectangle.Max.X, rectangle.Max.Y, depth), Vector2.Zero, color), + new ImmediateVertex(new Vector3(rectangle.Min.X, rectangle.Min.Y, depth), Vector2.Zero, color), + new ImmediateVertex(new Vector3(rectangle.Max.X, rectangle.Max.Y, depth), Vector2.Zero, color), + new ImmediateVertex(new Vector3(rectangle.Min.X, rectangle.Max.Y, depth), Vector2.Zero, color), + ]; + + int buffer = GL.GenBuffer(); + GL.BindBuffer(BufferTarget.ArrayBuffer, buffer); + GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * ImmediateVertex.Size, ref vertices[0], BufferUsage.StreamDraw); + + GL.BindVertexArray(_vao); + GL.VertexAttribPointer(_program_apos, 3, VertexAttribPointerType.Float, false, ImmediateVertex.Size, ImmediateVertex.PosOffset); + GL.EnableVertexAttribArray(_program_apos); + GL.VertexAttribPointer(_program_atexcoord, 2, VertexAttribPointerType.Float, false, ImmediateVertex.Size, ImmediateVertex.TexCoordsOffset); + GL.EnableVertexAttribArray(_program_atexcoord); + GL.VertexAttribPointer(_program_acolor, 4, VertexAttribPointerType.Float, false, ImmediateVertex.Size, ImmediateVertex.ColorOffset); + GL.EnableVertexAttribArray(_program_acolor); + + Size size = ((GLDeviceContext)Context).GLContext.FramebufferSize; + Matrix4x4 view = Matrix4x4.CreateOrthographicOffCenter(0, size.Width, 0, size.Height, 1, -1); + + GL.UseProgram(_program); + + GL.ActiveTexture(TextureUnit.Texture0); + GL.BindTexture(TextureTarget.Texture2d, _white); + + GL.UniformMatrix4f(_program_transforms, 1, true, ref view); + GL.Uniform1i(_program_image, 0); + + GL.DrawArrays(PrimitiveType.Triangles, 0, 6); + + GL.DeleteBuffer(buffer); + } + + public void Image(Box2d rectangle, Box2d uv, float depth, ITexture texture) + { + Span vertices = + [ + new ImmediateVertex(new Vector3(rectangle.Min.X, rectangle.Min.Y, depth), new Vector2(uv.Min.X, uv.Min.Y), Vector4.One), + new ImmediateVertex(new Vector3(rectangle.Max.X, rectangle.Min.Y, depth), new Vector2(uv.Max.X, uv.Min.Y), Vector4.One), + new ImmediateVertex(new Vector3(rectangle.Max.X, rectangle.Max.Y, depth), new Vector2(uv.Max.X, uv.Max.Y), Vector4.One), + new ImmediateVertex(new Vector3(rectangle.Min.X, rectangle.Min.Y, depth), new Vector2(uv.Min.X, uv.Min.Y), Vector4.One), + new ImmediateVertex(new Vector3(rectangle.Max.X, rectangle.Max.Y, depth), new Vector2(uv.Max.X, uv.Max.Y), Vector4.One), + new ImmediateVertex(new Vector3(rectangle.Min.X, rectangle.Max.Y, depth), new Vector2(uv.Min.X, uv.Max.Y), Vector4.One), + ]; + + int buffer = GL.GenBuffer(); + GL.BindBuffer(BufferTarget.ArrayBuffer, buffer); + GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * ImmediateVertex.Size, ref vertices[0], BufferUsage.StreamDraw); + + GL.BindVertexArray(_vao); + GL.VertexAttribPointer(_program_apos, 3, VertexAttribPointerType.Float, false, ImmediateVertex.Size, ImmediateVertex.PosOffset); + GL.EnableVertexAttribArray(_program_apos); + GL.VertexAttribPointer(_program_atexcoord, 2, VertexAttribPointerType.Float, false, ImmediateVertex.Size, ImmediateVertex.TexCoordsOffset); + GL.EnableVertexAttribArray(_program_atexcoord); + GL.VertexAttribPointer(_program_acolor, 4, VertexAttribPointerType.Float, false, ImmediateVertex.Size, ImmediateVertex.ColorOffset); + GL.EnableVertexAttribArray(_program_acolor); + Size size = ((GLDeviceContext)Context).GLContext.FramebufferSize; + Matrix4x4 view = Matrix4x4.CreateOrthographicOffCenter(0, size.Width, 0, size.Height, 1, -1); + + GL.UseProgram(_program); + + GL.ActiveTexture(TextureUnit.Texture0); + GL.BindTexture(TextureTarget.Texture2d, ((GLTexture)texture).Handle); + + GL.UniformMatrix4f(_program_transforms, 1, true, ref view); + GL.Uniform1i(_program_image, 0); + + GL.DrawArrays(PrimitiveType.Triangles, 0, 6); + + GL.DeleteBuffer(buffer); + } + + IContextBase IContextExtensionBase.Context => Context; + + void IContextExtensionBase.Require(IContextBase context) + { + Require((DeviceContext)context); + } + + [StructLayout(LayoutKind.Explicit, Pack = sizeof(float) * 4, Size = Size)] + private struct ImmediateVertex(Vector3 position, Vector2 texCoords, Vector4 color) + { + [FieldOffset(PosOffset)] public Vector3 Position = position; + [FieldOffset(TexCoordsOffset)] public Vector2 TexCoords = texCoords; + [FieldOffset(ColorOffset)] public Vector4 Color = color; + + public const int Size = 16 * sizeof(float); + public const int PosOffset = 0 * sizeof(float); + public const int TexCoordsOffset = 4 * sizeof(float); + public const int ColorOffset = 8 * sizeof(float); + } + } +} diff --git a/Dashboard.OpenGL/Drawing/immediate.frag b/Dashboard.OpenGL/Drawing/immediate.frag new file mode 100644 index 0000000..50d1dd6 --- /dev/null +++ b/Dashboard.OpenGL/Drawing/immediate.frag @@ -0,0 +1,12 @@ +#version 130 + +uniform sampler2D image; + +in vec2 vTexCoords; +in vec4 vColor; + +out vec4 fragColor; + +void main() { + fragColor = vColor * texture(image, vTexCoords); +} diff --git a/Dashboard.OpenGL/Drawing/immediate.vert b/Dashboard.OpenGL/Drawing/immediate.vert new file mode 100644 index 0000000..1d93786 --- /dev/null +++ b/Dashboard.OpenGL/Drawing/immediate.vert @@ -0,0 +1,18 @@ +#version 130 + +uniform mat4 transforms; + +in vec3 aPos; +in vec2 aTexCoords; +in vec4 aColor; + +out vec2 vTexCoords; +out vec4 vColor; + +void main() { + vec4 position = vec4(aPos, 1.0) * transforms; + gl_Position = position; + + vTexCoords = aTexCoords; + vColor = aColor; +} diff --git a/Dashboard.Drawing.OpenGL/Pal/GLDeviceContext.cs b/Dashboard.OpenGL/Pal/GLDeviceContext.cs similarity index 98% rename from Dashboard.Drawing.OpenGL/Pal/GLDeviceContext.cs rename to Dashboard.OpenGL/Pal/GLDeviceContext.cs index 29c489e..385a82e 100644 --- a/Dashboard.Drawing.OpenGL/Pal/GLDeviceContext.cs +++ b/Dashboard.OpenGL/Pal/GLDeviceContext.cs @@ -1,6 +1,7 @@ using System.Collections.Concurrent; using System.Collections.Immutable; using Dashboard.OpenGL; +using Dashboard.OpenGL.Drawing; using Dashboard.Pal; using OpenTK; using OpenTK.Graphics; @@ -62,6 +63,7 @@ namespace Dashboard.Drawing.OpenGL.Pal Extensions = extensions.ToImmutableHashSet(); ExtensionPreload(); + ExtensionPreload(); } public bool IsGLExtensionAvailable(string name) diff --git a/Dashboard.Drawing.OpenGL/Pal/GLTextureExtension.cs b/Dashboard.OpenGL/Pal/GLTextureExtension.cs similarity index 100% rename from Dashboard.Drawing.OpenGL/Pal/GLTextureExtension.cs rename to Dashboard.OpenGL/Pal/GLTextureExtension.cs diff --git a/Dashboard.OpenTK/PAL2/Pal2AppContext.cs b/Dashboard.OpenTK/PAL2/Pal2AppContext.cs index c603c9a..2db51eb 100644 --- a/Dashboard.OpenTK/PAL2/Pal2AppContext.cs +++ b/Dashboard.OpenTK/PAL2/Pal2AppContext.cs @@ -1,3 +1,4 @@ +using Dashboard.Drawing.OpenGL.Pal; using Dashboard.Windowing; using OpenTK.Graphics; using OpenTK.Platform; @@ -12,7 +13,6 @@ namespace Dashboard.OpenTK.PAL2 public override string DriverVendor => "Dashboard"; public override Version DriverVersion => new Version(0, 1); public GraphicsApiHints GraphicsApiHints { get; set; } = new OpenGLGraphicsApiHints(); - public bool OpenGLBindingsInitialized { get; private set; } = false; private readonly List _windows = new List(); @@ -21,14 +21,6 @@ namespace Dashboard.OpenTK.PAL2 PhysicalWindow window = new PhysicalWindow(GraphicsApiHints); _windows.Add(window); - if (!OpenGLBindingsInitialized) - { - OpenGLBindingsInitialized = true; - GLLoader.LoadBindings( - new Pal2BindingsContext(TK.OpenGL, - ((OpenGLDeviceContext)window.DeviceContext).ContextHandle)); - } - return window; } diff --git a/Dashboard.OpenTK/PAL2/OpenGLDeviceContext.cs b/Dashboard.OpenTK/PAL2/Pal2GLContext.cs similarity index 86% rename from Dashboard.OpenTK/PAL2/OpenGLDeviceContext.cs rename to Dashboard.OpenTK/PAL2/Pal2GLContext.cs index 100314d..7b8f7ca 100644 --- a/Dashboard.OpenTK/PAL2/OpenGLDeviceContext.cs +++ b/Dashboard.OpenTK/PAL2/Pal2GLContext.cs @@ -1,6 +1,7 @@ using System.Collections.Concurrent; using System.Drawing; using Dashboard.OpenGL; +using Dashboard.Pal; using Dashboard.Windowing; using OpenTK.Mathematics; using OpenTK.Platform; @@ -8,7 +9,7 @@ using TK = OpenTK.Platform.Toolkit; namespace Dashboard.OpenTK.PAL2 { - public class OpenGLDeviceContext : IGLContext, IGLDisposable + public class Pal2GLContext : IGLContext, IDisposable { public OpenGLContextHandle ContextHandle { get; } public WindowHandle WindowHandle { get; } @@ -27,12 +28,12 @@ namespace Dashboard.OpenTK.PAL2 public event Action? Disposed; - public OpenGLDeviceContext(WindowHandle window, OpenGLContextHandle context, ISwapGroup? group = null) + public Pal2GLContext(WindowHandle window, OpenGLContextHandle context) { WindowHandle = window; ContextHandle = context; - SwapGroup = group ?? new DummySwapGroup(context); - ContextGroup = GetContextGroup(context); + SwapGroup = new DummySwapGroup(context); + ContextGroup = GetContextGroup(ContextHandle); } public void MakeCurrent() @@ -45,18 +46,13 @@ namespace Dashboard.OpenTK.PAL2 return TK.OpenGL.GetProcedureAddress(ContextHandle, procName); } - private bool _isDisposed = false; - public void Dispose() => Dispose(true); - public void Dispose(bool safeExit) + protected void Dispose(bool isDisposing) { - if (_isDisposed) return; - _isDisposed = true; - if (SwapGroup is IGLDisposable glDisposable) { - glDisposable.Dispose(safeExit); + glDisposable.Dispose(isDisposing); } else if (SwapGroup is IDisposable disposable) { diff --git a/Dashboard.OpenTK/PAL2/PhysicalWindow.cs b/Dashboard.OpenTK/PAL2/PhysicalWindow.cs index d467408..437bbf6 100644 --- a/Dashboard.OpenTK/PAL2/PhysicalWindow.cs +++ b/Dashboard.OpenTK/PAL2/PhysicalWindow.cs @@ -1,7 +1,9 @@ using System.Collections.Concurrent; using System.Drawing; using Dashboard.Drawing; +using Dashboard.Drawing.OpenGL.Pal; using Dashboard.Events; +using Dashboard.Pal; using Dashboard.Windowing; using OpenTK.Mathematics; using OpenTK.Platform; @@ -14,7 +16,7 @@ namespace Dashboard.OpenTK.PAL2 { public DrawQueue DrawQueue { get; } = new DrawQueue(); public WindowHandle WindowHandle { get; } - public IDeviceContext DeviceContext { get; } + public DeviceContext DeviceContext { get; } public bool DoubleBuffered => true; // Always true for OpenTK windows. public IWindowManager? WindowManager { get; set; } @@ -52,17 +54,17 @@ namespace Dashboard.OpenTK.PAL2 public event EventHandler? MouseButtonUp; public event EventHandler? MouseScroll; - public PhysicalWindow(WindowHandle window, IDeviceContext dc) + public PhysicalWindow(WindowHandle window) { WindowHandle = window; - DeviceContext = dc; + DeviceContext = CreateDeviceContext(window, new OpenGLGraphicsApiHints()); AddWindow(this); } - public PhysicalWindow(WindowHandle window, OpenGLContextHandle context, ISwapGroup? swapGroup = null) + public PhysicalWindow(WindowHandle window, OpenGLContextHandle context) { WindowHandle = window; - DeviceContext = new OpenGLDeviceContext(window, context, swapGroup); + DeviceContext = new GLDeviceContext(new Pal2GLContext(window, context)); AddWindow(this); } @@ -73,14 +75,13 @@ namespace Dashboard.OpenTK.PAL2 AddWindow(this); } - private static IDeviceContext CreateDeviceContext(WindowHandle window, GraphicsApiHints hints) + private static DeviceContext CreateDeviceContext(WindowHandle window, GraphicsApiHints hints) { switch (hints.Api) { case GraphicsApi.OpenGL: case GraphicsApi.OpenGLES: - OpenGLContextHandle context = TK.OpenGL.CreateFromWindow(window); - return new OpenGLDeviceContext(window, context); + return new GLDeviceContext(new Pal2GLContext(window, TK.OpenGL.CreateFromWindow(window))); default: throw new Exception($"Unknown graphics API {hints.Api}."); } diff --git a/Dashboard/Controls/Control.cs b/Dashboard/Controls/Control.cs index 72c1a78..88fdfec 100644 --- a/Dashboard/Controls/Control.cs +++ b/Dashboard/Controls/Control.cs @@ -4,7 +4,7 @@ using Dashboard.Windowing; namespace Dashboard.Controls { - public class Control : IEventListener, IDrawQueuePaintable, IDisposable + public class Control : IEventListener, IDisposable { public string? Id { get; set; } public ClassSet Classes { get; } diff --git a/Dashboard/Controls/Form.cs b/Dashboard/Controls/Form.cs index cc39426..a25d57e 100644 --- a/Dashboard/Controls/Form.cs +++ b/Dashboard/Controls/Form.cs @@ -6,7 +6,6 @@ namespace Dashboard.Controls public class Form : Control { public IWindow Window { get; } - public override DrawQueue DrawQueue { get; } public override Box2d ClientArea { @@ -17,7 +16,6 @@ namespace Dashboard.Controls public Form(IWindow window) { Window = window; - DrawQueue = (window as IDrawQueuePaintable)?.DrawQueue ?? new DrawQueue(); } } } diff --git a/Dashboard/Controls/Label.cs b/Dashboard/Controls/Label.cs index f03339c..83fc447 100644 --- a/Dashboard/Controls/Label.cs +++ b/Dashboard/Controls/Label.cs @@ -27,11 +27,10 @@ namespace Dashboard.Controls ClientArea = new Box2d(ClientArea.Min, ClientArea.Min + (Vector2)sz); } - public override void OnPaint() { base.OnPaint(); DrawQueue.Text(new Vector3(ClientArea.Min, 0), TextBrush, Text, Font); } } -} \ No newline at end of file +} diff --git a/tests/Dashboard.TestApplication/Program.cs b/tests/Dashboard.TestApplication/Program.cs index 4a2786c..fe6f319 100644 --- a/tests/Dashboard.TestApplication/Program.cs +++ b/tests/Dashboard.TestApplication/Program.cs @@ -10,9 +10,11 @@ using OpenTK.Mathematics; using Box2d = Dashboard.Box2d; using TK = OpenTK.Platform.Toolkit; using Dashboard; +using Dashboard.Drawing.OpenGL.Pal; using Dashboard.Windowing; using OpenTK.Windowing.GraphicsLibraryFramework; using AppContext = Dashboard.Pal.AppContext; +using Vector4 = System.Numerics.Vector4; TK.Init(new ToolkitOptions() { @@ -51,13 +53,13 @@ PhysicalWindow window; SolidBrush fg = new SolidBrush(Color.FromArgb(0, 0, 0, 0)); SolidBrush bg = new SolidBrush(Color.Black); CancellationTokenSource source = new CancellationTokenSource(); -GLEngine engine; -ContextExecutor executor; -DimUI dimUI; +// GLEngine engine; +// ContextExecutor executor; +// DimUI dimUI; Vector2 mousePos = Vector2.Zero; Random r = new Random(); List points = new List(); -IFont font; +// IFont font; StringBuilder builder = new StringBuilder(); app.Initialize(); @@ -70,20 +72,20 @@ TK.Window.SetClientSize(window.WindowHandle, new Vector2i(320, 240)); TK.Window.SetBorderStyle(window.WindowHandle, WindowBorderStyle.ResizableBorder); // TK.Window.SetTransparencyMode(wnd, WindowTransparencyMode.TransparentFramebuffer, 0.1f); -OpenGLDeviceContext context = (OpenGLDeviceContext)window.DeviceContext; +GLDeviceContext context = (GLDeviceContext)window.DeviceContext; -context.MakeCurrent(); -context.SwapGroup.SwapInterval = 1; +context.GLContext.MakeCurrent(); +context.GLContext.SwapGroup.SwapInterval = 1; -engine = new GLEngine(); -engine.Initialize(); - -executor = engine.GetExecutor(context); - -dimUI = new DimUI(new DimUIConfig() -{ - Font = new NamedFont("Noto Sans", 9f), -}); +// engine = new GLEngine(); +// engine.Initialize(); +// +// executor = engine.GetExecutor(context); +// +// dimUI = new DimUI(new DimUIConfig() +// { +// Font = new NamedFont("Noto Sans", 9f), +// }); EventQueue.EventRaised += (handle, type, eventArgs) => { @@ -102,66 +104,66 @@ EventQueue.EventRaised += (handle, type, eventArgs) => }; TK.Window.SetMode(window.WindowHandle, WindowMode.Normal); -font = Typesetter.LoadFont("Nimbus Mono", 12f); +// font = Typesetter.LoadFont("Nimbus Mono", 12f); window.Painting += (sender, ea) => { - TK.Window.GetSize(context.WindowHandle, out Vector2i size); - executor.BeginFrame(); - - dimUI.Begin(new Box2d(0, 0, size.X, size.Y), window.DrawQueue); - dimUI.Text("Hello World!"); - dimUI.Button("Cancel"); dimUI.SameLine(); - dimUI.Button("OK"); - - dimUI.Input("type me!", builder); - - dimUI.BeginMenu(); - - if (dimUI.MenuItem("File")) - { - dimUI.BeginMenu(); - dimUI.MenuItem("New Window"); - dimUI.MenuItem("Preferences"); - dimUI.MenuItem("Exit"); - dimUI.EndMenu(); - } - - if (dimUI.MenuItem("Edit")) - { - dimUI.BeginMenu(); - dimUI.MenuItem("Cut"); - dimUI.MenuItem("Copy"); - dimUI.MenuItem("Paste"); - - if (dimUI.MenuItem("Send Char")) - { - dimUI.BeginMenu(); - dimUI.EndMenu(); - } - - dimUI.EndMenu(); - } - - if (dimUI.MenuItem("View")) - { - dimUI.BeginMenu(); - dimUI.MenuItem("Clear"); - - if (dimUI.MenuItem("Set Size")) - { - dimUI.BeginMenu(); - dimUI.MenuItem("24 x 40"); - dimUI.MenuItem("25 x 40"); - dimUI.MenuItem("24 x 80"); - dimUI.MenuItem("25 x 80"); - dimUI.MenuItem("25 x 120"); - dimUI.EndMenu(); - } - - dimUI.EndMenu(); - } - - dimUI.Finish(); + TK.Window.GetSize(window.WindowHandle, out Vector2i size); + // executor.BeginFrame(); + // + // dimUI.Begin(new Box2d(0, 0, size.X, size.Y), window.DrawQueue); + // dimUI.Text("Hello World!"); + // dimUI.Button("Cancel"); dimUI.SameLine(); + // dimUI.Button("OK"); + // + // dimUI.Input("type me!", builder); + // + // dimUI.BeginMenu(); + // + // if (dimUI.MenuItem("File")) + // { + // dimUI.BeginMenu(); + // dimUI.MenuItem("New Window"); + // dimUI.MenuItem("Preferences"); + // dimUI.MenuItem("Exit"); + // dimUI.EndMenu(); + // } + // + // if (dimUI.MenuItem("Edit")) + // { + // dimUI.BeginMenu(); + // dimUI.MenuItem("Cut"); + // dimUI.MenuItem("Copy"); + // dimUI.MenuItem("Paste"); + // + // if (dimUI.MenuItem("Send Char")) + // { + // dimUI.BeginMenu(); + // dimUI.EndMenu(); + // } + // + // dimUI.EndMenu(); + // } + // + // if (dimUI.MenuItem("View")) + // { + // dimUI.BeginMenu(); + // dimUI.MenuItem("Clear"); + // + // if (dimUI.MenuItem("Set Size")) + // { + // dimUI.BeginMenu(); + // dimUI.MenuItem("24 x 40"); + // dimUI.MenuItem("25 x 40"); + // dimUI.MenuItem("24 x 80"); + // dimUI.MenuItem("25 x 80"); + // dimUI.MenuItem("25 x 120"); + // dimUI.EndMenu(); + // } + // + // dimUI.EndMenu(); + // } + // + // dimUI.Finish(); GL.Viewport(0, 0, size.X, size.Y); GL.ClearColor(0.3f, 0.3f, 0.3f, 1.0f); @@ -171,10 +173,14 @@ window.Painting += (sender, ea) => { GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); GL.ColorMask(true, true, true, true); - executor.Draw(window.DrawQueue, new RectangleF(0, 0, size.X, size.Y), 1.5f /*(window as IDpiAwareWindow)?.Scale ?? 1*/); - executor.EndFrame(); + // executor.Draw(window.DrawQueue, new RectangleF(0, 0, size.X, size.Y), 1.5f /*(window as IDpiAwareWindow)?.Scale ?? 1*/); + // executor.EndFrame(); - context.SwapGroup.Swap(); + IImmediateMode imm = context.ExtensionRequire(); + imm.ClearColor(Color.Magenta); + imm.Line(new System.Numerics.Vector2(10, 10), new System.Numerics.Vector2(50, 50), 3, 0, new Vector4(0.2f, 0.2f, 1.0f, 1.0f)); + + context.GLContext.SwapGroup.Swap(); }; app.Run(true, source.Token);