Refactor rendering interfaces and implementations
- Refactored DirectRendering class to support new IDirectRendering interface and manage textures directly. - Enhanced ImmediateMode to utilize ImmediateVertex struct for immediate rendering calls. - Updated Image class to use IDirectRendering for texture creation. - Modified test application to demonstrate immediate mode rendering with new structures. - Removed obsolete code related to previous rendering abstractions.
This commit is contained in:
@@ -187,17 +187,8 @@ namespace Dashboard.Drawing
|
|||||||
|
|
||||||
public record struct UniformDescriptor(int Location, UniformType Type, long Offset, long Size);
|
public record struct UniformDescriptor(int Location, UniformType Type, long Offset, long Size);
|
||||||
|
|
||||||
public struct DrawCall(MeshPrimitive primitive, VertexSpecification vertexSpec, int first, int count)
|
public struct PipelineState()
|
||||||
{
|
{
|
||||||
public IShader? ShaderPipeline { get; init; }
|
|
||||||
public VertexSpecification VertexSpecification { get; init; } = vertexSpec;
|
|
||||||
|
|
||||||
public MeshPrimitive Primitive { get; init; } = primitive;
|
|
||||||
public int First { get; init; } = first;
|
|
||||||
public int Count { get; init; } = count;
|
|
||||||
public int BaseVertex { get; init; } = 0;
|
|
||||||
public long Offset { get; init; } = 0;
|
|
||||||
|
|
||||||
public Box2d ViewportRegion { get; init; } = new Box2d(Vector2.Zero, Vector2.PositiveInfinity);
|
public Box2d ViewportRegion { get; init; } = new Box2d(Vector2.Zero, Vector2.PositiveInfinity);
|
||||||
public Box2d ScissorRegion { get; init; } = new Box2d(Vector2.PositiveInfinity, Vector2.PositiveInfinity);
|
public Box2d ScissorRegion { get; init; } = new Box2d(Vector2.PositiveInfinity, Vector2.PositiveInfinity);
|
||||||
public WindingOrder FrontFace { get; init; } = WindingOrder.Counterclockwise;
|
public WindingOrder FrontFace { get; init; } = WindingOrder.Counterclockwise;
|
||||||
@@ -205,15 +196,41 @@ namespace Dashboard.Drawing
|
|||||||
public BlendMode BlendMode { get; init; } = BlendMode.Normal;
|
public BlendMode BlendMode { get; init; } = BlendMode.Normal;
|
||||||
public DepthMode DepthMode { get; init; } = DepthMode.Enabled;
|
public DepthMode DepthMode { get; init; } = DepthMode.Enabled;
|
||||||
public StencilMode StencilMode { get; init; } = StencilMode.Off;
|
public StencilMode StencilMode { get; init; } = StencilMode.Off;
|
||||||
public bool EnableRestart { get; init; } = false;
|
|
||||||
public long RestartIndex { get; init; } = -1;
|
|
||||||
public bool RedMask { get; init; } = true;
|
public bool RedMask { get; init; } = true;
|
||||||
public bool GreenMask { get; init; } = true;
|
public bool GreenMask { get; init; } = true;
|
||||||
public bool BlueMask { get; init; } = true;
|
public bool BlueMask { get; init; } = true;
|
||||||
public bool AlphaMask { get; init; } = true;
|
public bool AlphaMask { get; init; } = true;
|
||||||
public float PointSize { get; init; }= 1.0f;
|
public float PointSize { get; init; }= 1.0f;
|
||||||
public float LineWidth { get; init; }= 1.0f;
|
public float LineWidth { get; init; }= 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct DrawCall(MeshPrimitive primitive, VertexSpecification vertexSpec, int first, int count)
|
||||||
|
{
|
||||||
|
public IShader? ShaderPipeline { get; init; }
|
||||||
|
public PipelineState PipelineState { get; init; } = new PipelineState();
|
||||||
|
public VertexSpecification VertexSpecification { get; init; } = vertexSpec;
|
||||||
|
|
||||||
|
public MeshPrimitive Primitive { get; init; } = primitive;
|
||||||
|
public int First { get; init; } = first;
|
||||||
|
public int Count { get; init; } = count;
|
||||||
|
public int BaseVertex { get; init; } = 0;
|
||||||
|
public long Offset { get; init; } = 0;
|
||||||
|
public bool EnableRestart { get; init; } = false;
|
||||||
|
public long RestartIndex { get; init; } = -1;
|
||||||
|
|
||||||
|
public Box2d ViewportRegion => PipelineState.ViewportRegion;
|
||||||
|
public Box2d ScissorRegion => PipelineState.ScissorRegion;
|
||||||
|
public WindingOrder FrontFace => PipelineState.FrontFace;
|
||||||
|
public FaceCulling CullMode => PipelineState.CullMode;
|
||||||
|
public BlendMode BlendMode => PipelineState.BlendMode;
|
||||||
|
public DepthMode DepthMode => PipelineState.DepthMode;
|
||||||
|
public StencilMode StencilMode => PipelineState.StencilMode;
|
||||||
|
public bool RedMask => PipelineState.RedMask;
|
||||||
|
public bool GreenMask => PipelineState.GreenMask;
|
||||||
|
public bool BlueMask => PipelineState.BlueMask;
|
||||||
|
public bool AlphaMask => PipelineState.AlphaMask;
|
||||||
|
public float PointSize => PipelineState.PointSize;
|
||||||
|
public float LineWidth => PipelineState.LineWidth;
|
||||||
|
|
||||||
public List<ITexture?> Textures { get; init; } = [];
|
public List<ITexture?> Textures { get; init; } = [];
|
||||||
public List<UniformDescriptor> Uniforms { get; init; } = [];
|
public List<UniformDescriptor> Uniforms { get; init; } = [];
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
namespace Dashboard.Drawing
|
||||||
|
{
|
||||||
|
public enum BufferAccessPattern
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// No hint given. Not recommended.
|
||||||
|
/// </summary>
|
||||||
|
DontCare,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For buffers which have a long lifetime, but the contents are initialized once.
|
||||||
|
/// </summary>
|
||||||
|
Static,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For buffers which have a long lifetime, but the contents can be updated every frame.
|
||||||
|
/// </summary>
|
||||||
|
Stream,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For buffers which have a short lifetime, used for streaming resources to the graphics hardware.
|
||||||
|
/// </summary>
|
||||||
|
Upload,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For buffers which have a short lifetime, used for streaming resources from the graphics hardware.
|
||||||
|
/// </summary>
|
||||||
|
Download,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface IBuffer : IDisposable
|
||||||
|
{
|
||||||
|
public BufferAccessPattern AccessPattern { get; }
|
||||||
|
public long Size { get; }
|
||||||
|
|
||||||
|
void Reallocate(long newSize);
|
||||||
|
Span<T> Map<T>(long offset, int count = -1) where T : unmanaged;
|
||||||
|
void Unmap();
|
||||||
|
void Read<T>(long offset, Span<T> span) where T : unmanaged;
|
||||||
|
void Write<T>(long offset, ReadOnlySpan<T> span) where T : unmanaged;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,66 +2,49 @@ using Dashboard.Pal;
|
|||||||
|
|
||||||
namespace Dashboard.Drawing
|
namespace Dashboard.Drawing
|
||||||
{
|
{
|
||||||
public interface IShader : IDisposable
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Base interface for creating shader pipelines.
|
|
||||||
/// </summary>
|
|
||||||
public interface IShaderCreateInfo
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum BufferAccessPattern
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// No hint given. Not recommended.
|
|
||||||
/// </summary>
|
|
||||||
DontCare,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// For buffers which have a long lifetime, but the contents are initialized once.
|
|
||||||
/// </summary>
|
|
||||||
Static,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// For buffers which have a long lifetime, but the contents can be updated every frame.
|
|
||||||
/// </summary>
|
|
||||||
Stream,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// For buffers which have a short lifetime, used for streaming resources to the graphics hardware.
|
|
||||||
/// </summary>
|
|
||||||
Upload,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// For buffers which have a short lifetime, used for streaming resources from the graphics hardware.
|
|
||||||
/// </summary>
|
|
||||||
Download,
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IBuffer : IDisposable
|
|
||||||
{
|
|
||||||
public BufferAccessPattern AccessPattern { get; }
|
|
||||||
public long Size { get; }
|
|
||||||
|
|
||||||
void Reallocate(long newSize);
|
|
||||||
Span<T> Map<T>(long offset, int count = -1) where T : unmanaged;
|
|
||||||
void Unmap();
|
|
||||||
void Read<T>(long offset, Span<T> span) where T : unmanaged;
|
|
||||||
void Write<T>(long offset, ReadOnlySpan<T> span) where T : unmanaged;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This extension provides direct access to the backend rendering pipeline without writing with a higher level
|
/// This extension provides direct access to the backend rendering pipeline without writing with a higher level
|
||||||
/// abstraction than the rendering backend.
|
/// abstraction than the rendering backend.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IDirectRendering : IDeviceContextExtension
|
public interface IDirectRendering : IDeviceContextExtension
|
||||||
{
|
{
|
||||||
public IShader CreatePipeline<T>(T createInfo) where T : IShaderCreateInfo;
|
/// <summary>
|
||||||
public IBuffer CreateBuffer(BufferAccessPattern pattern, long size);
|
/// Create a shader program.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Type of the shader create info object.</typeparam>
|
||||||
|
/// <param name="createInfo">An object which describes how the shader is created.</param>
|
||||||
|
/// <returns>A shader program object.</returns>
|
||||||
|
/// <seealso cref="SpirvShaderCreateInfo"/>
|
||||||
|
/// <seealso cref="GlslShaderCreateInfo"/>
|
||||||
|
/// <seealso cref="GlslComputeShaderCreateInfo"/>
|
||||||
|
IShader CreateShader<T>(T createInfo) where T : IShaderCreateInfo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a texture object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">Type of texture to create.</param>
|
||||||
|
/// <returns>An empty texture object.</returns>
|
||||||
|
ITexture CreateTexture(TextureType type);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a buffer object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pattern">Buffer access pattern hint.</param>
|
||||||
|
/// <param name="size">Initial capacity of the buffer in bytes.</param>
|
||||||
|
/// <returns>An empty buffer object.</returns>
|
||||||
|
IBuffer CreateBuffer(BufferAccessPattern pattern, long size);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enqueue a draw call.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="drawCall">The draw call to enqueue.</param>
|
||||||
void Draw(DrawCall drawCall);
|
void Draw(DrawCall drawCall);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Obsolete("Use IDirectRendering instead.")]
|
||||||
|
public interface ITextureExtension : IDeviceContextExtension
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="IDirectRendering.CreateTexture(TextureType)"/>
|
||||||
|
ITexture CreateTexture(TextureType type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
using System.Data;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using Dashboard.Layout;
|
using Dashboard.Layout;
|
||||||
using Dashboard.Pal;
|
using Dashboard.Pal;
|
||||||
|
|
||||||
@@ -7,8 +9,57 @@ namespace Dashboard.Drawing
|
|||||||
{
|
{
|
||||||
public record struct RectangleDrawInfo(Vector2 Position, ComputedBox Box, Brush Fill, Brush? Border = null);
|
public record struct RectangleDrawInfo(Vector2 Position, ComputedBox Box, Brush Fill, Brush? Border = null);
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit, Size = Size)]
|
||||||
|
public struct ImmediateVertex()
|
||||||
|
{
|
||||||
|
[field: FieldOffset(PosOffset)]
|
||||||
|
public Vector3 Position { get; init; }= Vector3.Zero;
|
||||||
|
|
||||||
|
[field: FieldOffset(TexCoordsOffset)]
|
||||||
|
public Vector2 TexCoords { get; init; } = Vector2.Zero;
|
||||||
|
|
||||||
|
[field: FieldOffset(ColorOffset)]
|
||||||
|
public Vector4 Color { get; init; } = Vector4.One;
|
||||||
|
|
||||||
|
public ImmediateVertex(Vector3 position, Vector2 texCoords, Vector4 color) : this()
|
||||||
|
{
|
||||||
|
Position = position;
|
||||||
|
TexCoords = texCoords;
|
||||||
|
Color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImmediateVertex(Vector3 position, Vector2 texCoords, Color color)
|
||||||
|
: this(
|
||||||
|
position,
|
||||||
|
texCoords,
|
||||||
|
new Vector4(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ImmediateDrawCall(MeshPrimitive primitive, ReadOnlyMemory<ImmediateVertex> vertices)
|
||||||
|
{
|
||||||
|
public MeshPrimitive Primitive { get; init; } = primitive;
|
||||||
|
public ReadOnlyMemory<ImmediateVertex> Vertices { get; init; } = vertices;
|
||||||
|
public PipelineState PipelineState { get; init; } = new PipelineState();
|
||||||
|
public Matrix4x4 Transforms { get; init; } = Matrix4x4.Identity;
|
||||||
|
public ITexture? Texture { get; init; } = null;
|
||||||
|
}
|
||||||
|
|
||||||
public interface IImmediateMode : IDeviceContextExtension
|
public interface IImmediateMode : IDeviceContextExtension
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Enqueue a draw with the immediate mode shader pipeline.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="call">Information about this draw call.</param>
|
||||||
|
void DrawImmediate(ImmediateDrawCall call);
|
||||||
|
|
||||||
|
// TODO: move these to their own extension?
|
||||||
void Line(Vector2 a, Vector2 b, float width, float depth, Vector4 color);
|
void Line(Vector2 a, Vector2 b, float width, float depth, Vector4 color);
|
||||||
void Rectangle(Box2d rectangle, float depth, Vector4 color);
|
void Rectangle(Box2d rectangle, float depth, Vector4 color);
|
||||||
void Rectangle(in RectangleDrawInfo rectangle);
|
void Rectangle(in RectangleDrawInfo rectangle);
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace Dashboard.Drawing
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base interface for creating shader pipelines.
|
||||||
|
/// </summary>
|
||||||
|
public interface IShaderCreateInfo
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly record struct ShaderMappingProperty(string Name, int Index);
|
||||||
|
|
||||||
|
public interface IShader : IDisposable
|
||||||
|
{
|
||||||
|
public ImmutableList<ShaderMappingProperty> Attributes { get; }
|
||||||
|
public ImmutableList<ShaderMappingProperty> Uniforms { get; }
|
||||||
|
public ImmutableList<ShaderMappingProperty> Blocks { get; }
|
||||||
|
public ImmutableList<ShaderMappingProperty> Textures { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,7 @@
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using Dashboard.Pal;
|
|
||||||
|
|
||||||
namespace Dashboard.Drawing
|
namespace Dashboard.Drawing
|
||||||
{
|
{
|
||||||
public interface ITextureExtension : IDeviceContextExtension
|
|
||||||
{
|
|
||||||
ITexture CreateTexture(TextureType type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum TextureType
|
public enum TextureType
|
||||||
{
|
{
|
||||||
Texture1D,
|
Texture1D,
|
||||||
@@ -30,7 +30,7 @@ namespace Dashboard.Drawing
|
|||||||
if (Textures.TryGetValue(dc, out ITexture? texture))
|
if (Textures.TryGetValue(dc, out ITexture? texture))
|
||||||
return texture;
|
return texture;
|
||||||
|
|
||||||
ITextureExtension ext = dc.ExtensionRequire<ITextureExtension>();
|
IDirectRendering ext = dc.ExtensionRequire<IDirectRendering>();
|
||||||
texture = ext.CreateTexture(Type);
|
texture = ext.CreateTexture(Type);
|
||||||
texture.SetStorage(Format, Width, Height, Depth, Levels);
|
texture.SetStorage(Format, Width, Height, Depth, Levels);
|
||||||
for (int i = 0; i < Levels; i++)
|
for (int i = 0; i < Levels; i++)
|
||||||
|
|||||||
@@ -6,22 +6,38 @@ using OpenTK.Graphics.OpenGL;
|
|||||||
|
|
||||||
namespace Dashboard.OpenGL.Drawing
|
namespace Dashboard.OpenGL.Drawing
|
||||||
{
|
{
|
||||||
public class DirectRendering : IDirectRendering
|
public class DirectRendering : IDirectRendering, ITextureExtension
|
||||||
{
|
{
|
||||||
public DeviceContext Context { get; private set; } = null!;
|
public GLDeviceContext Context { get; private set; } = null!;
|
||||||
public string DriverName { get; } = "Dashboard OpenGL";
|
public string DriverName { get; } = "Dashboard OpenGL";
|
||||||
public string DriverVendor { get; } = "Dashboard";
|
public string DriverVendor { get; } = "Dashboard";
|
||||||
public Version DriverVersion { get; } = new Version(0, 1);
|
public Version DriverVersion { get; } = new Version(0, 1);
|
||||||
IContextBase IContextExtensionBase.Context => Context;
|
IContextBase IContextExtensionBase.Context => Context;
|
||||||
|
DeviceContext IContextExtensionBase<DeviceContext>.Context => Context;
|
||||||
|
|
||||||
|
public bool SupportsArbTextureStorage { get; private set; }
|
||||||
|
public bool SupportsAnisotropy { get; private set; }
|
||||||
|
|
||||||
private int _vao = -1;
|
private int _vao = -1;
|
||||||
|
private List<GLTexture> _textures = new List<GLTexture>();
|
||||||
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Require(DeviceContext context) => Context = context;
|
public void Require(DeviceContext context)
|
||||||
|
{
|
||||||
|
Context = (GLDeviceContext)context;
|
||||||
|
|
||||||
|
SupportsArbTextureStorage = Context.DriverVersion >= new Version(4, 2) ||
|
||||||
|
Context.IsGLExtensionAvailable("GL_ARB_texture_storage");
|
||||||
|
SupportsAnisotropy = Context.DriverVersion >= new Version() ||
|
||||||
|
Context.IsGLExtensionAvailable("GL_EXT_texture_filter_anisotropic") ||
|
||||||
|
Context.IsGLExtensionAvailable("GL_ARB_texture_filter_anisotropic");
|
||||||
|
}
|
||||||
|
|
||||||
public void Require(IContextBase context) => Require((DeviceContext)context);
|
public void Require(IContextBase context) => Require((DeviceContext)context);
|
||||||
|
|
||||||
public void Begin()
|
public void Begin()
|
||||||
@@ -37,7 +53,7 @@ namespace Dashboard.OpenGL.Drawing
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IShader CreatePipeline<T>(T createInfo) where T : IShaderCreateInfo
|
public IShader CreateShader<T>(T createInfo) where T : IShaderCreateInfo
|
||||||
{
|
{
|
||||||
int program = createInfo switch
|
int program = createInfo switch
|
||||||
{
|
{
|
||||||
@@ -74,5 +90,24 @@ namespace Dashboard.OpenGL.Drawing
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GLTexture CreateTexture(TextureType type)
|
||||||
|
{
|
||||||
|
GLTexture texture = new GLTexture(this, type);
|
||||||
|
lock (_textures) _textures.Add(texture);
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void TextureDisposed(GLTexture texture)
|
||||||
|
{
|
||||||
|
lock (_textures) _textures.Remove(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
ITexture ITextureExtension.CreateTexture(TextureType type) => CreateTexture(type);
|
||||||
|
|
||||||
|
ITexture IDirectRendering.CreateTexture(TextureType type)
|
||||||
|
{
|
||||||
|
return CreateTexture(type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,133 @@
|
|||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using Dashboard.Drawing;
|
using Dashboard.Drawing;
|
||||||
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
|
||||||
namespace Dashboard.OpenGL.Drawing
|
namespace Dashboard.OpenGL.Drawing
|
||||||
{
|
{
|
||||||
public class GLShader(GLDeviceContext context, int handle) : IShader
|
public class GLShader : IShader
|
||||||
{
|
{
|
||||||
public GLDeviceContext Context { get; } = context;
|
public GLDeviceContext Context { get; }
|
||||||
public int Handle { get; } = handle;
|
public int Handle { get; }
|
||||||
|
|
||||||
|
public ImmutableList<ShaderMappingProperty> Attributes { get; }
|
||||||
|
|
||||||
|
public ImmutableList<ShaderMappingProperty> Uniforms { get; }
|
||||||
|
|
||||||
|
public ImmutableList<ShaderMappingProperty> Blocks { get; }
|
||||||
|
|
||||||
|
public ImmutableList<ShaderMappingProperty> Textures { get; }
|
||||||
|
|
||||||
|
public GLShader(GLDeviceContext context, int handle)
|
||||||
|
{
|
||||||
|
Context = context;
|
||||||
|
Handle = handle;
|
||||||
|
|
||||||
|
List<ShaderMappingProperty> list = new List<ShaderMappingProperty>();
|
||||||
|
List<ShaderMappingProperty> list2 = new List<ShaderMappingProperty>();
|
||||||
|
|
||||||
|
int count = GL.GetProgrami(handle, ProgramProperty.ActiveAttributes);
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
list.Add(GetAttribute(handle, i));
|
||||||
|
}
|
||||||
|
Attributes = list.ToImmutableList();
|
||||||
|
|
||||||
|
list.Clear();
|
||||||
|
count = GL.GetProgrami(handle, ProgramProperty.ActiveUniforms);
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var property = GetUniform(handle, i, out bool isSampler);
|
||||||
|
list.Add(property);
|
||||||
|
if (isSampler)
|
||||||
|
list2.Add(property);
|
||||||
|
}
|
||||||
|
Uniforms = list.ToImmutableList();
|
||||||
|
Textures = list2.ToImmutableList();
|
||||||
|
|
||||||
|
list.Clear();
|
||||||
|
count = GL.GetProgrami(handle, ProgramProperty.ActiveUniformBlocks);
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var property = GetBlock(handle, i);
|
||||||
|
list.Add(property);
|
||||||
|
}
|
||||||
|
Blocks = list.ToImmutableList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ShaderMappingProperty GetAttribute(int program, int index)
|
||||||
|
{
|
||||||
|
string name = GL.GetActiveAttrib(program, (uint)index, 260, out _, out _, out _);
|
||||||
|
int location = GL.GetAttribLocation(program, name);
|
||||||
|
|
||||||
|
return new ShaderMappingProperty(name, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ShaderMappingProperty GetUniform(int program, int index, out bool isSampler)
|
||||||
|
{
|
||||||
|
string name = GL.GetActiveUniform(program, (uint)index, 260, out _, out _, out OpenTK.Graphics.OpenGL.UniformType type);
|
||||||
|
int location = GL.GetUniformLocation(program, name);
|
||||||
|
|
||||||
|
isSampler = type switch
|
||||||
|
{
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.Sampler1D or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.Sampler1DArray or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.Sampler1DShadow or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.Sampler1DArrayShadow or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.IntSampler1D or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.IntSampler1DArray or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.UnsignedIntSampler1D or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.UnsignedIntSampler1DArray or
|
||||||
|
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.Sampler2D or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.Sampler2DShadow or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.Sampler2DRect or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.Sampler2DRectShadow or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.Sampler2DArray or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.Sampler2DArrayShadow or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.Sampler2DMultisample or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.Sampler2DMultisampleArray or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.IntSampler2D or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.IntSampler2DRect or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.IntSampler2DArray or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.IntSampler2DMultisample or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.IntSampler2DMultisampleArray or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.UnsignedIntSampler2D or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.UnsignedIntSampler2DRect or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.UnsignedIntSampler2DArray or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.UnsignedIntSampler2DMultisample or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.UnsignedIntSampler2DMultisampleArray or
|
||||||
|
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.Sampler3D or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.IntSampler3D or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.UnsignedIntSampler3D or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.SamplerCube or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.SamplerCubeShadow or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.SamplerCubeMapArray or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.SamplerCubeMapArrayShadow or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.IntSamplerCube or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.IntSamplerCubeMapArray or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.UnsignedIntSamplerCube or
|
||||||
|
OpenTK.Graphics.OpenGL.UniformType.UnsignedIntSamplerCubeMapArray
|
||||||
|
=> true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
return new ShaderMappingProperty(name, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ShaderMappingProperty GetBlock(int program, int index)
|
||||||
|
{
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
GL.GetActiveUniformBlockiv(program, (uint)index, UniformBlockPName.UniformBlockDataSize, &size);
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.GetActiveUniformBlockName(program, (uint)index, 1024, out _, out string name);
|
||||||
|
return new ShaderMappingProperty(name, index);
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -221,16 +221,12 @@ namespace Dashboard.OpenGL.Drawing
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension(DrawCall call)
|
extension(PipelineState state)
|
||||||
{
|
{
|
||||||
public void UsePipeline() => GL.UseProgram((call.ShaderPipeline as GLShader)?.Handle ?? 0);
|
|
||||||
|
|
||||||
// TODO: clamp to viewport size
|
|
||||||
|
|
||||||
public void SetViewport(Vector2 size)
|
public void SetViewport(Vector2 size)
|
||||||
{
|
{
|
||||||
Vector2 min = Vector2.Max(Vector2.Zero, call.ViewportRegion.Min);
|
Vector2 min = Vector2.Max(Vector2.Zero, state.ViewportRegion.Min);
|
||||||
Vector2 max = Vector2.Min(size, call.ViewportRegion.Max);
|
Vector2 max = Vector2.Min(size, state.ViewportRegion.Max);
|
||||||
|
|
||||||
GL.Viewport(
|
GL.Viewport(
|
||||||
(int)Math.Round(min.X),
|
(int)Math.Round(min.X),
|
||||||
@@ -239,9 +235,10 @@ namespace Dashboard.OpenGL.Drawing
|
|||||||
(int)Math.Round(max.Y - min.Y));
|
(int)Math.Round(max.Y - min.Y));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: clamp to viewport size
|
||||||
public void SetScissor(Vector2 size)
|
public void SetScissor(Vector2 size)
|
||||||
{
|
{
|
||||||
if (call.ScissorRegion == new Box2d(Vector2.PositiveInfinity, Vector2.PositiveInfinity))
|
if (state.ScissorRegion == new Box2d(Vector2.PositiveInfinity, Vector2.PositiveInfinity))
|
||||||
{
|
{
|
||||||
GL.Disable(EnableCap.ScissorTest);
|
GL.Disable(EnableCap.ScissorTest);
|
||||||
return;
|
return;
|
||||||
@@ -249,15 +246,15 @@ namespace Dashboard.OpenGL.Drawing
|
|||||||
|
|
||||||
GL.Enable(EnableCap.ScissorTest);
|
GL.Enable(EnableCap.ScissorTest);
|
||||||
GL.Scissor(
|
GL.Scissor(
|
||||||
(int)Math.Round(call.ViewportRegion.Left),
|
(int)Math.Round(state.ViewportRegion.Left),
|
||||||
(int)Math.Round(size.Y - call.ViewportRegion.Top),
|
(int)Math.Round(size.Y - state.ViewportRegion.Top),
|
||||||
(int)Math.Round(call.ViewportRegion.Right - call.ViewportRegion.Left),
|
(int)Math.Round(state.ViewportRegion.Right - state.ViewportRegion.Left),
|
||||||
(int)Math.Round(call.ViewportRegion.Bottom - call.ViewportRegion.Top));
|
(int)Math.Round(state.ViewportRegion.Bottom - state.ViewportRegion.Top));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetFrontFace()
|
public void SetFrontFace()
|
||||||
{
|
{
|
||||||
GL.FrontFace(call.FrontFace switch
|
GL.FrontFace(state.FrontFace switch
|
||||||
{
|
{
|
||||||
WindingOrder.Clockwise => FrontFaceDirection.Cw,
|
WindingOrder.Clockwise => FrontFaceDirection.Cw,
|
||||||
WindingOrder.Counterclockwise => FrontFaceDirection.Ccw,
|
WindingOrder.Counterclockwise => FrontFaceDirection.Ccw,
|
||||||
@@ -267,7 +264,7 @@ namespace Dashboard.OpenGL.Drawing
|
|||||||
|
|
||||||
public void SetCullMode()
|
public void SetCullMode()
|
||||||
{
|
{
|
||||||
if (call.CullMode == FaceCulling.None)
|
if (state.CullMode == FaceCulling.None)
|
||||||
{
|
{
|
||||||
GL.Disable(EnableCap.CullFace);
|
GL.Disable(EnableCap.CullFace);
|
||||||
return;
|
return;
|
||||||
@@ -275,7 +272,7 @@ namespace Dashboard.OpenGL.Drawing
|
|||||||
|
|
||||||
GL.Enable(EnableCap.CullFace);
|
GL.Enable(EnableCap.CullFace);
|
||||||
|
|
||||||
GL.CullFace(call.CullMode switch
|
GL.CullFace(state.CullMode switch
|
||||||
{
|
{
|
||||||
FaceCulling.Both => TriangleFace.FrontAndBack,
|
FaceCulling.Both => TriangleFace.FrontAndBack,
|
||||||
FaceCulling.Front => TriangleFace.Front,
|
FaceCulling.Front => TriangleFace.Front,
|
||||||
@@ -284,9 +281,47 @@ namespace Dashboard.OpenGL.Drawing
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetBlendMode() => call.BlendMode.SetAll();
|
public void SetBlendMode() => state.BlendMode.SetAll();
|
||||||
public void SetDepthMode() => call.DepthMode.SetAll();
|
public void SetDepthMode() => state.DepthMode.SetAll();
|
||||||
public void SetStencilMode() => call.StencilMode.SetAll();
|
public void SetStencilMode() => state.StencilMode.SetAll();
|
||||||
|
|
||||||
|
public void SetColorMask()
|
||||||
|
{
|
||||||
|
GL.ColorMask(state.RedMask, state.GreenMask, state.BlueMask, state.AlphaMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetPointSize()
|
||||||
|
{
|
||||||
|
GL.PointSize(state.PointSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetLineWidth()
|
||||||
|
{
|
||||||
|
GL.LineWidth(state.LineWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension(DrawCall call)
|
||||||
|
{
|
||||||
|
public void UsePipeline() => GL.UseProgram((call.ShaderPipeline as GLShader)?.Handle ?? 0);
|
||||||
|
|
||||||
|
public void SetViewport(Vector2 size) => call.PipelineState.SetViewport(size);
|
||||||
|
|
||||||
|
public void SetScissor(Vector2 size) => call.PipelineState.SetViewport(size);
|
||||||
|
|
||||||
|
public void SetFrontFace() => call.PipelineState.SetFrontFace();
|
||||||
|
|
||||||
|
public void SetCullMode() => call.PipelineState.SetCullMode();
|
||||||
|
|
||||||
|
public void SetBlendMode() => call.PipelineState.BlendMode.SetAll();
|
||||||
|
public void SetDepthMode() => call.PipelineState.DepthMode.SetAll();
|
||||||
|
public void SetStencilMode() => call.PipelineState.StencilMode.SetAll();
|
||||||
|
|
||||||
|
public void SetColorMask() => call.PipelineState.SetColorMask();
|
||||||
|
|
||||||
|
public void SetPointSize() => call.PipelineState.SetPointSize();
|
||||||
|
|
||||||
|
public void SetLineWidth() => call.PipelineState.SetLineWidth();
|
||||||
|
|
||||||
public void SetPrimitiveRestart()
|
public void SetPrimitiveRestart()
|
||||||
{
|
{
|
||||||
@@ -300,21 +335,6 @@ namespace Dashboard.OpenGL.Drawing
|
|||||||
GL.PrimitiveRestartIndex((uint)call.RestartIndex);
|
GL.PrimitiveRestartIndex((uint)call.RestartIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetColorMask()
|
|
||||||
{
|
|
||||||
GL.ColorMask(call.RedMask, call.GreenMask, call.BlueMask, call.AlphaMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetPointSize()
|
|
||||||
{
|
|
||||||
GL.PointSize(call.PointSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetLineWidth()
|
|
||||||
{
|
|
||||||
GL.LineWidth(call.LineWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UseTextures()
|
public void UseTextures()
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|||||||
@@ -1,61 +1,12 @@
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using Dashboard.Drawing;
|
using Dashboard.Drawing;
|
||||||
using Dashboard.Pal;
|
using Dashboard.OpenGL.Drawing;
|
||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
using OGL = OpenTK.Graphics.OpenGL;
|
using OGL = OpenTK.Graphics.OpenGL;
|
||||||
|
|
||||||
namespace Dashboard.OpenGL
|
namespace Dashboard.OpenGL
|
||||||
{
|
{
|
||||||
public class GLTextureExtension : ITextureExtension, IContextExtensionBase<GLDeviceContext>
|
public class GLTexture(DirectRendering extension, TextureType type) : ITexture
|
||||||
{
|
|
||||||
public string DriverName => "Dashboard OpenGL Texture Extension";
|
|
||||||
public string DriverVendor => "Dashboard";
|
|
||||||
public Version DriverVersion => new Version(0, 1, 0);
|
|
||||||
public GLDeviceContext Context { get; private set; } = null!;
|
|
||||||
public bool SupportsArbTextureStorage { get; private set; }
|
|
||||||
public bool SupportsAnisotropy { get; private set; }
|
|
||||||
|
|
||||||
IContextBase IContextExtensionBase.Context => Context;
|
|
||||||
DeviceContext IContextExtensionBase<DeviceContext>.Context => Context;
|
|
||||||
|
|
||||||
private List<GLTexture> _textures = new List<GLTexture>();
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Require(GLDeviceContext context)
|
|
||||||
{
|
|
||||||
Context = context;
|
|
||||||
|
|
||||||
SupportsArbTextureStorage = Context.DriverVersion >= new Version(4, 2) ||
|
|
||||||
Context.IsGLExtensionAvailable("GL_ARB_texture_storage");
|
|
||||||
SupportsAnisotropy = Context.DriverVersion >= new Version() ||
|
|
||||||
Context.IsGLExtensionAvailable("GL_EXT_texture_filter_anisotropic") ||
|
|
||||||
Context.IsGLExtensionAvailable("GL_ARB_texture_filter_anisotropic");
|
|
||||||
}
|
|
||||||
public void Require(DeviceContext context) => Require((GLDeviceContext)context);
|
|
||||||
public void Require(IContextBase context) => Require((GLDeviceContext)context);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public GLTexture CreateTexture(TextureType type)
|
|
||||||
{
|
|
||||||
GLTexture texture = new GLTexture(this, type);
|
|
||||||
lock (_textures) _textures.Add(texture);
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void TextureDisposed(GLTexture texture)
|
|
||||||
{
|
|
||||||
lock (_textures) _textures.Remove(texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
ITexture ITextureExtension.CreateTexture(TextureType type) => CreateTexture(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GLTexture(GLTextureExtension extension, TextureType type) : ITexture
|
|
||||||
{
|
{
|
||||||
public int Handle { get; private set; } = 0;
|
public int Handle { get; private set; } = 0;
|
||||||
public bool IsValid => Handle != 0;
|
public bool IsValid => Handle != 0;
|
||||||
@@ -87,7 +38,7 @@ namespace Dashboard.OpenGL
|
|||||||
_ => throw new NotSupportedException()
|
_ => throw new NotSupportedException()
|
||||||
};
|
};
|
||||||
|
|
||||||
private GLTextureExtension Extension { get; } = extension;
|
private DirectRendering Extension { get; } = extension;
|
||||||
private GLDeviceContext Context => Extension.Context;
|
private GLDeviceContext Context => Extension.Context;
|
||||||
|
|
||||||
~GLTexture()
|
~GLTexture()
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime;
|
using System.Runtime;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using Dashboard.Drawing;
|
using Dashboard.Drawing;
|
||||||
using Dashboard.Pal;
|
using Dashboard.Pal;
|
||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
@@ -16,14 +19,16 @@ namespace Dashboard.OpenGL.Drawing
|
|||||||
|
|
||||||
public DeviceContext Context { get; private set; } = null!;
|
public DeviceContext Context { get; private set; } = null!;
|
||||||
|
|
||||||
private int _program;
|
private IDirectRendering _dr;
|
||||||
|
private GLShader _program;
|
||||||
|
|
||||||
private uint _program_apos;
|
private uint _program_apos;
|
||||||
private uint _program_atexcoord;
|
private uint _program_atexcoord;
|
||||||
private uint _program_acolor;
|
private uint _program_acolor;
|
||||||
private int _program_transforms;
|
private int _program_transforms;
|
||||||
private int _program_image;
|
private int _program_image;
|
||||||
private int _vao;
|
private int _vao;
|
||||||
private int _white;
|
private GLTexture _white;
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
@@ -32,43 +37,36 @@ namespace Dashboard.OpenGL.Drawing
|
|||||||
public void Require(DeviceContext context)
|
public void Require(DeviceContext context)
|
||||||
{
|
{
|
||||||
Context = context;
|
Context = context;
|
||||||
|
_dr = context.ExtensionRequire<IDirectRendering>();
|
||||||
|
|
||||||
_program = GL.CreateProgram();
|
GlslShaderCreateInfo shader;
|
||||||
|
|
||||||
int vs = GL.CreateShader(ShaderType.VertexShader);
|
using (StreamReader vertex = new StreamReader(GetType().Assembly
|
||||||
|
|
||||||
using (StreamReader reader = new StreamReader(GetType().Assembly
|
|
||||||
.GetManifestResourceStream("Dashboard.OpenGL.Drawing.immediate.vert")!))
|
.GetManifestResourceStream("Dashboard.OpenGL.Drawing.immediate.vert")!))
|
||||||
{
|
using (StreamReader fragment = new StreamReader(GetType().Assembly
|
||||||
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")!))
|
.GetManifestResourceStream("Dashboard.OpenGL.Drawing.immediate.frag")!))
|
||||||
{
|
{
|
||||||
GL.ShaderSource(fs, reader.ReadToEnd());
|
shader = new GlslShaderCreateInfo()
|
||||||
|
{
|
||||||
|
VertexShader = vertex.ReadToEnd(),
|
||||||
|
FragmentShader = fragment.ReadToEnd(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
GL.CompileShader(fs);
|
_program = (GLShader)_dr.CreateShader(shader);
|
||||||
GL.AttachShader(_program, fs);
|
|
||||||
|
|
||||||
GL.LinkProgram(_program);
|
_program_apos = (uint)GL.GetAttribLocation(_program.Handle, "aPos");
|
||||||
GL.DeleteShader(vs); GL.DeleteShader(fs);
|
_program_atexcoord = (uint)GL.GetAttribLocation(_program.Handle, "aTexCoords");
|
||||||
|
_program_acolor = (uint)GL.GetAttribLocation(_program.Handle, "aColor");
|
||||||
|
|
||||||
_program_apos = (uint)GL.GetAttribLocation(_program, "aPos");
|
_program_transforms = GL.GetUniformLocation(_program.Handle, "transforms");
|
||||||
_program_atexcoord = (uint)GL.GetAttribLocation(_program, "aTexCoords");
|
_program_image = GL.GetUniformLocation(_program.Handle, "image");
|
||||||
_program_acolor = (uint)GL.GetAttribLocation(_program, "aColor");
|
|
||||||
|
|
||||||
_program_transforms = GL.GetUniformLocation(_program, "transforms");
|
_white = (GLTexture)_dr.CreateTexture(TextureType.Texture2D);
|
||||||
_program_image = GL.GetUniformLocation(_program, "image");
|
_white.SetStorage(PixelFormat.Rgb8I, 1, 1, 1, 1);
|
||||||
|
|
||||||
GL.GenTexture(out _white);
|
GL.BindTexture(TextureTarget.Texture2D, _white.Handle);
|
||||||
GL.BindTexture(TextureTarget.Texture2D, _white);
|
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, 1, 1, OpenTK.Graphics.OpenGL.PixelFormat.Rgb, PixelType.Byte, stackalloc byte[] { 0xFF, 0xFF, 0xFF, 0xFF });
|
||||||
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.TextureSwizzleA, (int)All.One);
|
||||||
GL.TexParameteri(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleR, (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.TextureSwizzleG, (int)All.One);
|
||||||
@@ -113,10 +111,10 @@ namespace Dashboard.OpenGL.Drawing
|
|||||||
|
|
||||||
Matrix4x4 view = Context.ExtensionRequire<IDeviceContextBase>().Transforms;
|
Matrix4x4 view = Context.ExtensionRequire<IDeviceContextBase>().Transforms;
|
||||||
|
|
||||||
GL.UseProgram(_program);
|
GL.UseProgram(_program.Handle);
|
||||||
|
|
||||||
GL.ActiveTexture(TextureUnit.Texture0);
|
GL.ActiveTexture(TextureUnit.Texture0);
|
||||||
GL.BindTexture(TextureTarget.Texture2D, _white);
|
GL.BindTexture(TextureTarget.Texture2D, _white.Handle);
|
||||||
|
|
||||||
GL.UniformMatrix4f(_program_transforms, 1, true, ref view);
|
GL.UniformMatrix4f(_program_transforms, 1, true, ref view);
|
||||||
GL.Uniform1i(_program_image, 0);
|
GL.Uniform1i(_program_image, 0);
|
||||||
@@ -152,10 +150,10 @@ namespace Dashboard.OpenGL.Drawing
|
|||||||
|
|
||||||
Matrix4x4 view = Context.ExtensionRequire<IDeviceContextBase>().Transforms;
|
Matrix4x4 view = Context.ExtensionRequire<IDeviceContextBase>().Transforms;
|
||||||
|
|
||||||
GL.UseProgram(_program);
|
GL.UseProgram(_program.Handle);
|
||||||
|
|
||||||
GL.ActiveTexture(TextureUnit.Texture0);
|
GL.ActiveTexture(TextureUnit.Texture0);
|
||||||
GL.BindTexture(TextureTarget.Texture2D, _white);
|
GL.BindTexture(TextureTarget.Texture2D, _white.Handle);
|
||||||
|
|
||||||
GL.UniformMatrix4f(_program_transforms, 1, true, ref view);
|
GL.UniformMatrix4f(_program_transforms, 1, true, ref view);
|
||||||
GL.Uniform1i(_program_image, 0);
|
GL.Uniform1i(_program_image, 0);
|
||||||
@@ -204,7 +202,7 @@ namespace Dashboard.OpenGL.Drawing
|
|||||||
GL.EnableVertexAttribArray(_program_acolor);
|
GL.EnableVertexAttribArray(_program_acolor);
|
||||||
Matrix4x4 view = Context.ExtensionRequire<IDeviceContextBase>().Transforms;
|
Matrix4x4 view = Context.ExtensionRequire<IDeviceContextBase>().Transforms;
|
||||||
|
|
||||||
GL.UseProgram(_program);
|
GL.UseProgram(_program.Handle);
|
||||||
|
|
||||||
GL.ActiveTexture(TextureUnit.Texture0);
|
GL.ActiveTexture(TextureUnit.Texture0);
|
||||||
GL.BindTexture(TextureTarget.Texture2D, ((GLTexture)texture).Handle);
|
GL.BindTexture(TextureTarget.Texture2D, ((GLTexture)texture).Handle);
|
||||||
@@ -224,17 +222,53 @@ namespace Dashboard.OpenGL.Drawing
|
|||||||
Require((DeviceContext)context);
|
Require((DeviceContext)context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Explicit, Pack = sizeof(float) * 4, Size = Size)]
|
public void DrawImmediate(ImmediateDrawCall call)
|
||||||
private struct ImmediateVertex(Vector3 position, Vector2 texCoords, Vector4 color)
|
|
||||||
{
|
{
|
||||||
[FieldOffset(PosOffset)] public Vector3 Position = position;
|
// This is a terrible implementation as it stands but we can improve this immensely later on.
|
||||||
[FieldOffset(TexCoordsOffset)] public Vector2 TexCoords = texCoords;
|
IDirectRendering dr = Context.ExtensionRequire<IDirectRendering>();
|
||||||
[FieldOffset(ColorOffset)] public Vector4 Color = color;
|
|
||||||
|
|
||||||
public const int Size = 16 * sizeof(float);
|
int size = call.Vertices.Length * ImmediateVertex.Size;
|
||||||
public const int PosOffset = 0 * sizeof(float);
|
|
||||||
public const int TexCoordsOffset = 4 * sizeof(float);
|
IBuffer buffer = dr.CreateBuffer(BufferAccessPattern.Stream, size);
|
||||||
public const int ColorOffset = 8 * sizeof(float);
|
buffer.Write(0, call.Vertices.Span);
|
||||||
|
|
||||||
|
VertexSpecification spec = CreateVertexSpec(buffer);
|
||||||
|
ReadOnlyMemory<byte> uniforms = MemoryMarshal.AsBytes(stackalloc Matrix4x4[] {call.Transforms}).ToArray();
|
||||||
|
|
||||||
|
DrawCall drawCall = new DrawCall(call.Primitive, spec, 0, call.Vertices.Length)
|
||||||
|
{
|
||||||
|
ShaderPipeline = _program,
|
||||||
|
PipelineState = call.PipelineState,
|
||||||
|
UniformData = uniforms,
|
||||||
|
Uniforms = [
|
||||||
|
new UniformDescriptor() {
|
||||||
|
Location = _program_transforms,
|
||||||
|
Type = Dashboard.Drawing.UniformType.Mat4,
|
||||||
|
Offset = 0,
|
||||||
|
Size = Unsafe.SizeOf<Matrix4x4>(),
|
||||||
|
}
|
||||||
|
],
|
||||||
|
Textures = [call.Texture ?? _white]
|
||||||
|
};
|
||||||
|
|
||||||
|
dr.Draw(drawCall);
|
||||||
|
buffer.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private VertexSpecification CreateVertexSpec(IBuffer buffer)
|
||||||
|
{
|
||||||
|
return new VertexSpecification(
|
||||||
|
[
|
||||||
|
new VertexAttribute((int)_program_apos, 3, VertexAttributeType.Float, ImmediateVertex.PosOffset, ImmediateVertex.Size),
|
||||||
|
new VertexAttribute((int)_program_atexcoord, 2, VertexAttributeType.Float, ImmediateVertex.TexCoordsOffset, ImmediateVertex.Size),
|
||||||
|
new VertexAttribute((int)_program_acolor, 4, VertexAttributeType.Float, ImmediateVertex.ColorOffset, ImmediateVertex.Size)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
buffer,
|
||||||
|
buffer,
|
||||||
|
buffer
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,6 @@ namespace Dashboard.OpenGL
|
|||||||
Extensions = extensions.ToImmutableHashSet();
|
Extensions = extensions.ToImmutableHashSet();
|
||||||
|
|
||||||
ExtensionPreload<DeviceContextBase>();
|
ExtensionPreload<DeviceContextBase>();
|
||||||
ExtensionPreload<GLTextureExtension>();
|
|
||||||
ExtensionPreload<ImmediateMode>();
|
ExtensionPreload<ImmediateMode>();
|
||||||
ExtensionPreload<DirectRendering>();
|
ExtensionPreload<DirectRendering>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{9D6CCC74
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dashboard.TestApplication", "tests\Dashboard.TestApplication\Dashboard.TestApplication.csproj", "{7C90B90B-DF31-439B-9080-CD805383B014}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dashboard.TestApplication", "tests\Dashboard.TestApplication\Dashboard.TestApplication.csproj", "{7C90B90B-DF31-439B-9080-CD805383B014}"
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
{1BDFEF50-C907-42C8-B63B-E4F6F585CFB5} = {1BDFEF50-C907-42C8-B63B-E4F6F585CFB5}
|
|
||||||
{49A62F46-AC1C-4240-8615-020D4FBBF964} = {49A62F46-AC1C-4240-8615-020D4FBBF964}
|
{49A62F46-AC1C-4240-8615-020D4FBBF964} = {49A62F46-AC1C-4240-8615-020D4FBBF964}
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
|
|||||||
@@ -74,64 +74,21 @@ TK.Window.SetMode(window.WindowHandle, WindowMode.Normal);
|
|||||||
window.DeviceContext.ExtensionRequire<IDeviceContextBase>().ScaleOverride = 1.5f;
|
window.DeviceContext.ExtensionRequire<IDeviceContextBase>().ScaleOverride = 1.5f;
|
||||||
|
|
||||||
IDirectRendering direct = window.DeviceContext.ExtensionRequire<IDirectRendering>();
|
IDirectRendering direct = window.DeviceContext.ExtensionRequire<IDirectRendering>();
|
||||||
IBuffer vertex = direct.CreateBuffer(BufferAccessPattern.Static, 1024);
|
IImmediateMode imm = window.DeviceContext.ExtensionRequire<IImmediateMode>();
|
||||||
float[] vertices = new float[]
|
ImmediateVertex[] vertices = new ImmediateVertex[]
|
||||||
{ // x, y, z, _, r, g, b, a
|
{ // x, y, z, r, g, b, a
|
||||||
-0.5f, -0.5f, 0.0f, 0.0f, 1, 0, 0, 1,
|
new ImmediateVertex(new System.Numerics.Vector3(-0.5f, -0.5f, 0.0f), System.Numerics.Vector2.Zero, new System.Numerics.Vector4(1, 0, 0, 1)),
|
||||||
+0.5f, -0.5f, 0.0f, 0.0f, 0, 1, 0, 1,
|
new ImmediateVertex(new System.Numerics.Vector3(+0.5f, -0.5f, 0.0f), System.Numerics.Vector2.Zero, new System.Numerics.Vector4(0, 1, 0, 1)),
|
||||||
+0.0f, +0.5f, 0.0f, 0.0f, 0, 0, 1, 1,
|
new ImmediateVertex(new System.Numerics.Vector3(+0.0f, +0.5f, 0.0f), System.Numerics.Vector2.Zero, new System.Numerics.Vector4(0, 0, 1, 1)),
|
||||||
};
|
};
|
||||||
vertex.Write(0, vertices);
|
|
||||||
|
|
||||||
IShader shader = direct.CreatePipeline(new GlslShaderCreateInfo()
|
|
||||||
{
|
|
||||||
VertexShader =
|
|
||||||
"""
|
|
||||||
#version 410
|
|
||||||
layout (location = 0) in vec3 apos;
|
|
||||||
layout (location = 1) in vec4 acolor;
|
|
||||||
|
|
||||||
out vec4 vcolor;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
gl_Position = vec4(apos, 1);
|
|
||||||
vcolor = acolor;
|
|
||||||
}
|
|
||||||
""",
|
|
||||||
FragmentShader =
|
|
||||||
"""
|
|
||||||
#version 410
|
|
||||||
in vec4 vcolor;
|
|
||||||
out vec4 fcolor;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
fcolor = vcolor;
|
|
||||||
}
|
|
||||||
|
|
||||||
""",
|
|
||||||
});
|
|
||||||
|
|
||||||
VertexSpecification spec = new VertexSpecification(
|
|
||||||
[
|
|
||||||
new VertexAttribute(0, 3, VertexAttributeType.Float, 0, 8 * sizeof(float)),
|
|
||||||
new VertexAttribute(1, 4, VertexAttributeType.Float, 4 * sizeof(float), 8 * sizeof(float))
|
|
||||||
],
|
|
||||||
[vertex, vertex]
|
|
||||||
);
|
|
||||||
|
|
||||||
DrawCall call = new DrawCall(MeshPrimitive.Triangle, spec, 0, 3)
|
|
||||||
{
|
|
||||||
ShaderPipeline = shader
|
|
||||||
};
|
|
||||||
|
|
||||||
window.EventRaised += (sender, eventArgs) =>
|
window.EventRaised += (sender, eventArgs) =>
|
||||||
{
|
{
|
||||||
if (eventArgs is not PaintEventArgs paint)
|
if (eventArgs is not PaintEventArgs paint)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
paint.DeviceContext.ExtensionRequire<IDirectRendering>().Draw(call);
|
imm.DrawImmediate(new ImmediateDrawCall(MeshPrimitive.Triangle, vertices.AsMemory()));
|
||||||
};
|
};
|
||||||
|
|
||||||
app.Run(true, source.Token);
|
app.Run(true, source.Token);
|
||||||
|
|||||||
Reference in New Issue
Block a user