Implement new immediate mode.

This commit is contained in:
H. Utku Maden 2025-11-12 21:24:25 +03:00
parent 6e8888df48
commit 2932b3b85e
21 changed files with 427 additions and 118 deletions

View File

@ -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);
}
}

View File

@ -1,6 +1,7 @@
using System.Drawing; using System.Drawing;
using Dashboard.Pal;
namespace Dashboard.Pal namespace Dashboard.Drawing
{ {
public interface ITextureExtension : IDeviceContextExtension public interface ITextureExtension : IDeviceContextExtension
{ {

View File

@ -1,5 +1,6 @@
using Dashboard.Collections; using Dashboard.Collections;
using Dashboard.Windowing; using Dashboard.Windowing;
using BindingFlags = System.Reflection.BindingFlags;
namespace Dashboard.Pal namespace Dashboard.Pal
{ {
@ -94,7 +95,7 @@ namespace Dashboard.Pal
return _preloadedExtensions.Add<T>(() => new T()); return _preloadedExtensions.Add<T>(() => new T());
} }
public T ExtensionRequire<T>() where T : IAppContextExtension, new() public T ExtensionRequire<T>() where T : IAppContextExtension
{ {
T? extension = default; T? extension = default;
@ -112,7 +113,8 @@ namespace Dashboard.Pal
} }
else else
{ {
extension = new T(); extension = (T?)typeof(T).GetConstructor(BindingFlags.Public, [])?.Invoke([]) ??
throw new Exception("Constructor not found.");
} }
_extensions.Add(extension); _extensions.Add(extension);

View File

@ -1,4 +1,5 @@
using Dashboard.Collections; using Dashboard.Collections;
using BindingFlags = System.Reflection.BindingFlags;
namespace Dashboard.Pal namespace Dashboard.Pal
{ {
@ -41,7 +42,7 @@ namespace Dashboard.Pal
return _preloadedExtensions.Add<T>(() => new T()); return _preloadedExtensions.Add<T>(() => new T());
} }
public T ExtensionRequire<T>() where T : IDeviceContextExtension, new() public T ExtensionRequire<T>() where T : IDeviceContextExtension
{ {
T? extension = default; T? extension = default;
@ -59,7 +60,9 @@ namespace Dashboard.Pal
} }
else 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); _extensions.Add(extension);

View File

@ -63,7 +63,7 @@ namespace Dashboard.Pal
/// </summary> /// </summary>
/// <typeparam name="T">The extension to require.</typeparam> /// <typeparam name="T">The extension to require.</typeparam>
/// <returns>The extension instance.</returns> /// <returns>The extension instance.</returns>
T ExtensionRequire<T>() where T : TExtension, new(); T ExtensionRequire<T>() where T : TExtension;
} }
/// <summary> /// <summary>

View File

@ -1,5 +1,6 @@
using System.Drawing; using System.Drawing;
using Dashboard.Events; using Dashboard.Events;
using Dashboard.Pal;
namespace Dashboard.Windowing namespace Dashboard.Windowing
{ {
@ -59,7 +60,7 @@ namespace Dashboard.Windowing
/// <summary> /// <summary>
/// The device context for this window. /// The device context for this window.
/// </summary> /// </summary>
IDeviceContext DeviceContext { get; } DeviceContext DeviceContext { get; }
/// <summary> /// <summary>
/// True if the window is double buffered. /// True if the window is double buffered.

View File

@ -9,7 +9,6 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="BlurgText" Version="0.1.0-nightly-19" /> <PackageReference Include="BlurgText" Version="0.1.0-nightly-19" />
<PackageReference Include="OpenTK.Graphics" Version="[5.0.0-pre.*,5.1)" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -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
{
}
}

View File

@ -4,10 +4,19 @@
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="OpenTK.Graphics" Version="[5.0.0-pre.*,5.1)" />
<ProjectReference Include="..\Dashboard.Common\Dashboard.Common.csproj" /> <ProjectReference Include="..\Dashboard.Common\Dashboard.Common.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Remove="Drawing\immediate.frag" />
<EmbeddedResource Include="Drawing\immediate.frag" />
<None Remove="Drawing\immediate.vert" />
<EmbeddedResource Include="Drawing\immediate.vert" />
</ItemGroup>
</Project> </Project>

View File

@ -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<ImmediateVertex> 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<ImmediateVertex> 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<ImmediateVertex> 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);
}
}
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -1,6 +1,7 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Immutable; using System.Collections.Immutable;
using Dashboard.OpenGL; using Dashboard.OpenGL;
using Dashboard.OpenGL.Drawing;
using Dashboard.Pal; using Dashboard.Pal;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
@ -62,6 +63,7 @@ namespace Dashboard.Drawing.OpenGL.Pal
Extensions = extensions.ToImmutableHashSet(); Extensions = extensions.ToImmutableHashSet();
ExtensionPreload<GLTextureExtension>(); ExtensionPreload<GLTextureExtension>();
ExtensionPreload<ImmediateMode>();
} }
public bool IsGLExtensionAvailable(string name) public bool IsGLExtensionAvailable(string name)

View File

@ -1,3 +1,4 @@
using Dashboard.Drawing.OpenGL.Pal;
using Dashboard.Windowing; using Dashboard.Windowing;
using OpenTK.Graphics; using OpenTK.Graphics;
using OpenTK.Platform; using OpenTK.Platform;
@ -12,7 +13,6 @@ namespace Dashboard.OpenTK.PAL2
public override string DriverVendor => "Dashboard"; public override string DriverVendor => "Dashboard";
public override Version DriverVersion => new Version(0, 1); public override Version DriverVersion => new Version(0, 1);
public GraphicsApiHints GraphicsApiHints { get; set; } = new OpenGLGraphicsApiHints(); public GraphicsApiHints GraphicsApiHints { get; set; } = new OpenGLGraphicsApiHints();
public bool OpenGLBindingsInitialized { get; private set; } = false;
private readonly List<PhysicalWindow> _windows = new List<PhysicalWindow>(); private readonly List<PhysicalWindow> _windows = new List<PhysicalWindow>();
@ -21,14 +21,6 @@ namespace Dashboard.OpenTK.PAL2
PhysicalWindow window = new PhysicalWindow(GraphicsApiHints); PhysicalWindow window = new PhysicalWindow(GraphicsApiHints);
_windows.Add(window); _windows.Add(window);
if (!OpenGLBindingsInitialized)
{
OpenGLBindingsInitialized = true;
GLLoader.LoadBindings(
new Pal2BindingsContext(TK.OpenGL,
((OpenGLDeviceContext)window.DeviceContext).ContextHandle));
}
return window; return window;
} }

View File

@ -1,6 +1,7 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Drawing; using System.Drawing;
using Dashboard.OpenGL; using Dashboard.OpenGL;
using Dashboard.Pal;
using Dashboard.Windowing; using Dashboard.Windowing;
using OpenTK.Mathematics; using OpenTK.Mathematics;
using OpenTK.Platform; using OpenTK.Platform;
@ -8,7 +9,7 @@ using TK = OpenTK.Platform.Toolkit;
namespace Dashboard.OpenTK.PAL2 namespace Dashboard.OpenTK.PAL2
{ {
public class OpenGLDeviceContext : IGLContext, IGLDisposable public class Pal2GLContext : IGLContext, IDisposable
{ {
public OpenGLContextHandle ContextHandle { get; } public OpenGLContextHandle ContextHandle { get; }
public WindowHandle WindowHandle { get; } public WindowHandle WindowHandle { get; }
@ -27,12 +28,12 @@ namespace Dashboard.OpenTK.PAL2
public event Action? Disposed; public event Action? Disposed;
public OpenGLDeviceContext(WindowHandle window, OpenGLContextHandle context, ISwapGroup? group = null) public Pal2GLContext(WindowHandle window, OpenGLContextHandle context)
{ {
WindowHandle = window; WindowHandle = window;
ContextHandle = context; ContextHandle = context;
SwapGroup = group ?? new DummySwapGroup(context); SwapGroup = new DummySwapGroup(context);
ContextGroup = GetContextGroup(context); ContextGroup = GetContextGroup(ContextHandle);
} }
public void MakeCurrent() public void MakeCurrent()
@ -45,18 +46,13 @@ namespace Dashboard.OpenTK.PAL2
return TK.OpenGL.GetProcedureAddress(ContextHandle, procName); return TK.OpenGL.GetProcedureAddress(ContextHandle, procName);
} }
private bool _isDisposed = false;
public void Dispose() => Dispose(true); 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) if (SwapGroup is IGLDisposable glDisposable)
{ {
glDisposable.Dispose(safeExit); glDisposable.Dispose(isDisposing);
} }
else if (SwapGroup is IDisposable disposable) else if (SwapGroup is IDisposable disposable)
{ {

View File

@ -1,7 +1,9 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Drawing; using System.Drawing;
using Dashboard.Drawing; using Dashboard.Drawing;
using Dashboard.Drawing.OpenGL.Pal;
using Dashboard.Events; using Dashboard.Events;
using Dashboard.Pal;
using Dashboard.Windowing; using Dashboard.Windowing;
using OpenTK.Mathematics; using OpenTK.Mathematics;
using OpenTK.Platform; using OpenTK.Platform;
@ -14,7 +16,7 @@ namespace Dashboard.OpenTK.PAL2
{ {
public DrawQueue DrawQueue { get; } = new DrawQueue(); public DrawQueue DrawQueue { get; } = new DrawQueue();
public WindowHandle WindowHandle { get; } public WindowHandle WindowHandle { get; }
public IDeviceContext DeviceContext { get; } public DeviceContext DeviceContext { get; }
public bool DoubleBuffered => true; // Always true for OpenTK windows. public bool DoubleBuffered => true; // Always true for OpenTK windows.
public IWindowManager? WindowManager { get; set; } public IWindowManager? WindowManager { get; set; }
@ -52,17 +54,17 @@ namespace Dashboard.OpenTK.PAL2
public event EventHandler<MouseButtonEventArgs>? MouseButtonUp; public event EventHandler<MouseButtonEventArgs>? MouseButtonUp;
public event EventHandler<MouseScrollEventArgs>? MouseScroll; public event EventHandler<MouseScrollEventArgs>? MouseScroll;
public PhysicalWindow(WindowHandle window, IDeviceContext dc) public PhysicalWindow(WindowHandle window)
{ {
WindowHandle = window; WindowHandle = window;
DeviceContext = dc; DeviceContext = CreateDeviceContext(window, new OpenGLGraphicsApiHints());
AddWindow(this); AddWindow(this);
} }
public PhysicalWindow(WindowHandle window, OpenGLContextHandle context, ISwapGroup? swapGroup = null) public PhysicalWindow(WindowHandle window, OpenGLContextHandle context)
{ {
WindowHandle = window; WindowHandle = window;
DeviceContext = new OpenGLDeviceContext(window, context, swapGroup); DeviceContext = new GLDeviceContext(new Pal2GLContext(window, context));
AddWindow(this); AddWindow(this);
} }
@ -73,14 +75,13 @@ namespace Dashboard.OpenTK.PAL2
AddWindow(this); AddWindow(this);
} }
private static IDeviceContext CreateDeviceContext(WindowHandle window, GraphicsApiHints hints) private static DeviceContext CreateDeviceContext(WindowHandle window, GraphicsApiHints hints)
{ {
switch (hints.Api) switch (hints.Api)
{ {
case GraphicsApi.OpenGL: case GraphicsApi.OpenGL:
case GraphicsApi.OpenGLES: case GraphicsApi.OpenGLES:
OpenGLContextHandle context = TK.OpenGL.CreateFromWindow(window); return new GLDeviceContext(new Pal2GLContext(window, TK.OpenGL.CreateFromWindow(window)));
return new OpenGLDeviceContext(window, context);
default: default:
throw new Exception($"Unknown graphics API {hints.Api}."); throw new Exception($"Unknown graphics API {hints.Api}.");
} }

View File

@ -4,7 +4,7 @@ using Dashboard.Windowing;
namespace Dashboard.Controls namespace Dashboard.Controls
{ {
public class Control : IEventListener, IDrawQueuePaintable, IDisposable public class Control : IEventListener, IDisposable
{ {
public string? Id { get; set; } public string? Id { get; set; }
public ClassSet Classes { get; } public ClassSet Classes { get; }

View File

@ -6,7 +6,6 @@ namespace Dashboard.Controls
public class Form : Control public class Form : Control
{ {
public IWindow Window { get; } public IWindow Window { get; }
public override DrawQueue DrawQueue { get; }
public override Box2d ClientArea public override Box2d ClientArea
{ {
@ -17,7 +16,6 @@ namespace Dashboard.Controls
public Form(IWindow window) public Form(IWindow window)
{ {
Window = window; Window = window;
DrawQueue = (window as IDrawQueuePaintable)?.DrawQueue ?? new DrawQueue();
} }
} }
} }

View File

@ -27,7 +27,6 @@ namespace Dashboard.Controls
ClientArea = new Box2d(ClientArea.Min, ClientArea.Min + (Vector2)sz); ClientArea = new Box2d(ClientArea.Min, ClientArea.Min + (Vector2)sz);
} }
public override void OnPaint() public override void OnPaint()
{ {
base.OnPaint(); base.OnPaint();

View File

@ -10,9 +10,11 @@ using OpenTK.Mathematics;
using Box2d = Dashboard.Box2d; using Box2d = Dashboard.Box2d;
using TK = OpenTK.Platform.Toolkit; using TK = OpenTK.Platform.Toolkit;
using Dashboard; using Dashboard;
using Dashboard.Drawing.OpenGL.Pal;
using Dashboard.Windowing; using Dashboard.Windowing;
using OpenTK.Windowing.GraphicsLibraryFramework; using OpenTK.Windowing.GraphicsLibraryFramework;
using AppContext = Dashboard.Pal.AppContext; using AppContext = Dashboard.Pal.AppContext;
using Vector4 = System.Numerics.Vector4;
TK.Init(new ToolkitOptions() TK.Init(new ToolkitOptions()
{ {
@ -51,13 +53,13 @@ PhysicalWindow window;
SolidBrush fg = new SolidBrush(Color.FromArgb(0, 0, 0, 0)); SolidBrush fg = new SolidBrush(Color.FromArgb(0, 0, 0, 0));
SolidBrush bg = new SolidBrush(Color.Black); SolidBrush bg = new SolidBrush(Color.Black);
CancellationTokenSource source = new CancellationTokenSource(); CancellationTokenSource source = new CancellationTokenSource();
GLEngine engine; // GLEngine engine;
ContextExecutor executor; // ContextExecutor executor;
DimUI dimUI; // DimUI dimUI;
Vector2 mousePos = Vector2.Zero; Vector2 mousePos = Vector2.Zero;
Random r = new Random(); Random r = new Random();
List<Vector3> points = new List<Vector3>(); List<Vector3> points = new List<Vector3>();
IFont font; // IFont font;
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
app.Initialize(); app.Initialize();
@ -70,20 +72,20 @@ TK.Window.SetClientSize(window.WindowHandle, new Vector2i(320, 240));
TK.Window.SetBorderStyle(window.WindowHandle, WindowBorderStyle.ResizableBorder); TK.Window.SetBorderStyle(window.WindowHandle, WindowBorderStyle.ResizableBorder);
// TK.Window.SetTransparencyMode(wnd, WindowTransparencyMode.TransparentFramebuffer, 0.1f); // TK.Window.SetTransparencyMode(wnd, WindowTransparencyMode.TransparentFramebuffer, 0.1f);
OpenGLDeviceContext context = (OpenGLDeviceContext)window.DeviceContext; GLDeviceContext context = (GLDeviceContext)window.DeviceContext;
context.MakeCurrent(); context.GLContext.MakeCurrent();
context.SwapGroup.SwapInterval = 1; context.GLContext.SwapGroup.SwapInterval = 1;
engine = new GLEngine(); // engine = new GLEngine();
engine.Initialize(); // engine.Initialize();
//
executor = engine.GetExecutor(context); // executor = engine.GetExecutor(context);
//
dimUI = new DimUI(new DimUIConfig() // dimUI = new DimUI(new DimUIConfig()
{ // {
Font = new NamedFont("Noto Sans", 9f), // Font = new NamedFont("Noto Sans", 9f),
}); // });
EventQueue.EventRaised += (handle, type, eventArgs) => EventQueue.EventRaised += (handle, type, eventArgs) =>
{ {
@ -102,66 +104,66 @@ EventQueue.EventRaised += (handle, type, eventArgs) =>
}; };
TK.Window.SetMode(window.WindowHandle, WindowMode.Normal); TK.Window.SetMode(window.WindowHandle, WindowMode.Normal);
font = Typesetter.LoadFont("Nimbus Mono", 12f); // font = Typesetter.LoadFont("Nimbus Mono", 12f);
window.Painting += (sender, ea) => { window.Painting += (sender, ea) => {
TK.Window.GetSize(context.WindowHandle, out Vector2i size); TK.Window.GetSize(window.WindowHandle, out Vector2i size);
executor.BeginFrame(); // executor.BeginFrame();
//
dimUI.Begin(new Box2d(0, 0, size.X, size.Y), window.DrawQueue); // dimUI.Begin(new Box2d(0, 0, size.X, size.Y), window.DrawQueue);
dimUI.Text("Hello World!"); // dimUI.Text("Hello World!");
dimUI.Button("Cancel"); dimUI.SameLine(); // dimUI.Button("Cancel"); dimUI.SameLine();
dimUI.Button("OK"); // dimUI.Button("OK");
//
dimUI.Input("type me!", builder); // dimUI.Input("type me!", builder);
//
dimUI.BeginMenu(); // dimUI.BeginMenu();
//
if (dimUI.MenuItem("File")) // if (dimUI.MenuItem("File"))
{ // {
dimUI.BeginMenu(); // dimUI.BeginMenu();
dimUI.MenuItem("New Window"); // dimUI.MenuItem("New Window");
dimUI.MenuItem("Preferences"); // dimUI.MenuItem("Preferences");
dimUI.MenuItem("Exit"); // dimUI.MenuItem("Exit");
dimUI.EndMenu(); // dimUI.EndMenu();
} // }
//
if (dimUI.MenuItem("Edit")) // if (dimUI.MenuItem("Edit"))
{ // {
dimUI.BeginMenu(); // dimUI.BeginMenu();
dimUI.MenuItem("Cut"); // dimUI.MenuItem("Cut");
dimUI.MenuItem("Copy"); // dimUI.MenuItem("Copy");
dimUI.MenuItem("Paste"); // dimUI.MenuItem("Paste");
//
if (dimUI.MenuItem("Send Char")) // if (dimUI.MenuItem("Send Char"))
{ // {
dimUI.BeginMenu(); // dimUI.BeginMenu();
dimUI.EndMenu(); // dimUI.EndMenu();
} // }
//
dimUI.EndMenu(); // dimUI.EndMenu();
} // }
//
if (dimUI.MenuItem("View")) // if (dimUI.MenuItem("View"))
{ // {
dimUI.BeginMenu(); // dimUI.BeginMenu();
dimUI.MenuItem("Clear"); // dimUI.MenuItem("Clear");
//
if (dimUI.MenuItem("Set Size")) // if (dimUI.MenuItem("Set Size"))
{ // {
dimUI.BeginMenu(); // dimUI.BeginMenu();
dimUI.MenuItem("24 x 40"); // dimUI.MenuItem("24 x 40");
dimUI.MenuItem("25 x 40"); // dimUI.MenuItem("25 x 40");
dimUI.MenuItem("24 x 80"); // dimUI.MenuItem("24 x 80");
dimUI.MenuItem("25 x 80"); // dimUI.MenuItem("25 x 80");
dimUI.MenuItem("25 x 120"); // dimUI.MenuItem("25 x 120");
dimUI.EndMenu(); // dimUI.EndMenu();
} // }
//
dimUI.EndMenu(); // dimUI.EndMenu();
} // }
//
dimUI.Finish(); // dimUI.Finish();
GL.Viewport(0, 0, size.X, size.Y); GL.Viewport(0, 0, size.X, size.Y);
GL.ClearColor(0.3f, 0.3f, 0.3f, 1.0f); 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.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
GL.ColorMask(true, true, true, true); 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.Draw(window.DrawQueue, new RectangleF(0, 0, size.X, size.Y), 1.5f /*(window as IDpiAwareWindow)?.Scale ?? 1*/);
executor.EndFrame(); // executor.EndFrame();
context.SwapGroup.Swap(); IImmediateMode imm = context.ExtensionRequire<IImmediateMode>();
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); app.Run(true, source.Token);