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 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 ScissorRegion { get; init; } = new Box2d(Vector2.PositiveInfinity, Vector2.PositiveInfinity);
|
||||
public WindingOrder FrontFace { get; init; } = WindingOrder.Counterclockwise;
|
||||
@@ -205,15 +196,41 @@ namespace Dashboard.Drawing
|
||||
public BlendMode BlendMode { get; init; } = BlendMode.Normal;
|
||||
public DepthMode DepthMode { get; init; } = DepthMode.Enabled;
|
||||
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 GreenMask { get; init; } = true;
|
||||
public bool BlueMask { get; init; } = true;
|
||||
public bool AlphaMask { get; init; } = true;
|
||||
public float PointSize { 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<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
|
||||
{
|
||||
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>
|
||||
/// This extension provides direct access to the backend rendering pipeline without writing with a higher level
|
||||
/// abstraction than the rendering backend.
|
||||
/// </summary>
|
||||
public interface IDirectRendering : IDeviceContextExtension
|
||||
{
|
||||
public IShader CreatePipeline<T>(T createInfo) where T : IShaderCreateInfo;
|
||||
public IBuffer CreateBuffer(BufferAccessPattern pattern, long size);
|
||||
/// <summary>
|
||||
/// 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);
|
||||
}
|
||||
|
||||
[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.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using Dashboard.Layout;
|
||||
using Dashboard.Pal;
|
||||
|
||||
@@ -7,8 +9,57 @@ namespace Dashboard.Drawing
|
||||
{
|
||||
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
|
||||
{
|
||||
/// <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 Rectangle(Box2d rectangle, float depth, Vector4 color);
|
||||
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 Dashboard.Pal;
|
||||
|
||||
namespace Dashboard.Drawing
|
||||
{
|
||||
public interface ITextureExtension : IDeviceContextExtension
|
||||
{
|
||||
ITexture CreateTexture(TextureType type);
|
||||
}
|
||||
|
||||
public enum TextureType
|
||||
{
|
||||
Texture1D,
|
||||
@@ -30,7 +30,7 @@ namespace Dashboard.Drawing
|
||||
if (Textures.TryGetValue(dc, out ITexture? texture))
|
||||
return texture;
|
||||
|
||||
ITextureExtension ext = dc.ExtensionRequire<ITextureExtension>();
|
||||
IDirectRendering ext = dc.ExtensionRequire<IDirectRendering>();
|
||||
texture = ext.CreateTexture(Type);
|
||||
texture.SetStorage(Format, Width, Height, Depth, Levels);
|
||||
for (int i = 0; i < Levels; i++)
|
||||
|
||||
@@ -6,22 +6,38 @@ using OpenTK.Graphics.OpenGL;
|
||||
|
||||
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 DriverVendor { get; } = "Dashboard";
|
||||
public Version DriverVersion { get; } = new Version(0, 1);
|
||||
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 List<GLTexture> _textures = new List<GLTexture>();
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
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 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
|
||||
{
|
||||
@@ -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 OpenTK.Graphics.OpenGL;
|
||||
|
||||
namespace Dashboard.OpenGL.Drawing
|
||||
{
|
||||
public class GLShader(GLDeviceContext context, int handle) : IShader
|
||||
public class GLShader : IShader
|
||||
{
|
||||
public GLDeviceContext Context { get; } = context;
|
||||
public int Handle { get; } = handle;
|
||||
public GLDeviceContext Context { get; }
|
||||
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()
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
Vector2 min = Vector2.Max(Vector2.Zero, call.ViewportRegion.Min);
|
||||
Vector2 max = Vector2.Min(size, call.ViewportRegion.Max);
|
||||
Vector2 min = Vector2.Max(Vector2.Zero, state.ViewportRegion.Min);
|
||||
Vector2 max = Vector2.Min(size, state.ViewportRegion.Max);
|
||||
|
||||
GL.Viewport(
|
||||
(int)Math.Round(min.X),
|
||||
@@ -239,9 +235,10 @@ namespace Dashboard.OpenGL.Drawing
|
||||
(int)Math.Round(max.Y - min.Y));
|
||||
}
|
||||
|
||||
// TODO: clamp to viewport 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);
|
||||
return;
|
||||
@@ -249,15 +246,15 @@ namespace Dashboard.OpenGL.Drawing
|
||||
|
||||
GL.Enable(EnableCap.ScissorTest);
|
||||
GL.Scissor(
|
||||
(int)Math.Round(call.ViewportRegion.Left),
|
||||
(int)Math.Round(size.Y - call.ViewportRegion.Top),
|
||||
(int)Math.Round(call.ViewportRegion.Right - call.ViewportRegion.Left),
|
||||
(int)Math.Round(call.ViewportRegion.Bottom - call.ViewportRegion.Top));
|
||||
(int)Math.Round(state.ViewportRegion.Left),
|
||||
(int)Math.Round(size.Y - state.ViewportRegion.Top),
|
||||
(int)Math.Round(state.ViewportRegion.Right - state.ViewportRegion.Left),
|
||||
(int)Math.Round(state.ViewportRegion.Bottom - state.ViewportRegion.Top));
|
||||
}
|
||||
|
||||
public void SetFrontFace()
|
||||
{
|
||||
GL.FrontFace(call.FrontFace switch
|
||||
GL.FrontFace(state.FrontFace switch
|
||||
{
|
||||
WindingOrder.Clockwise => FrontFaceDirection.Cw,
|
||||
WindingOrder.Counterclockwise => FrontFaceDirection.Ccw,
|
||||
@@ -267,7 +264,7 @@ namespace Dashboard.OpenGL.Drawing
|
||||
|
||||
public void SetCullMode()
|
||||
{
|
||||
if (call.CullMode == FaceCulling.None)
|
||||
if (state.CullMode == FaceCulling.None)
|
||||
{
|
||||
GL.Disable(EnableCap.CullFace);
|
||||
return;
|
||||
@@ -275,7 +272,7 @@ namespace Dashboard.OpenGL.Drawing
|
||||
|
||||
GL.Enable(EnableCap.CullFace);
|
||||
|
||||
GL.CullFace(call.CullMode switch
|
||||
GL.CullFace(state.CullMode switch
|
||||
{
|
||||
FaceCulling.Both => TriangleFace.FrontAndBack,
|
||||
FaceCulling.Front => TriangleFace.Front,
|
||||
@@ -284,9 +281,47 @@ namespace Dashboard.OpenGL.Drawing
|
||||
});
|
||||
}
|
||||
|
||||
public void SetBlendMode() => call.BlendMode.SetAll();
|
||||
public void SetDepthMode() => call.DepthMode.SetAll();
|
||||
public void SetStencilMode() => call.StencilMode.SetAll();
|
||||
public void SetBlendMode() => state.BlendMode.SetAll();
|
||||
public void SetDepthMode() => state.DepthMode.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()
|
||||
{
|
||||
@@ -300,21 +335,6 @@ namespace Dashboard.OpenGL.Drawing
|
||||
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()
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
@@ -1,61 +1,12 @@
|
||||
using System.Drawing;
|
||||
using Dashboard.Drawing;
|
||||
using Dashboard.Pal;
|
||||
using Dashboard.OpenGL.Drawing;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using OGL = OpenTK.Graphics.OpenGL;
|
||||
|
||||
namespace Dashboard.OpenGL
|
||||
{
|
||||
public class GLTextureExtension : ITextureExtension, IContextExtensionBase<GLDeviceContext>
|
||||
{
|
||||
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 class GLTexture(DirectRendering extension, TextureType type) : ITexture
|
||||
{
|
||||
public int Handle { get; private set; } = 0;
|
||||
public bool IsValid => Handle != 0;
|
||||
@@ -87,7 +38,7 @@ namespace Dashboard.OpenGL
|
||||
_ => throw new NotSupportedException()
|
||||
};
|
||||
|
||||
private GLTextureExtension Extension { get; } = extension;
|
||||
private DirectRendering Extension { get; } = extension;
|
||||
private GLDeviceContext Context => Extension.Context;
|
||||
|
||||
~GLTexture()
|
||||
@@ -1,7 +1,10 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Drawing;
|
||||
using System.Numerics;
|
||||
using System.Runtime;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using Dashboard.Drawing;
|
||||
using Dashboard.Pal;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
@@ -16,14 +19,16 @@ namespace Dashboard.OpenGL.Drawing
|
||||
|
||||
public DeviceContext Context { get; private set; } = null!;
|
||||
|
||||
private int _program;
|
||||
private IDirectRendering _dr;
|
||||
private GLShader _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;
|
||||
private GLTexture _white;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
@@ -32,43 +37,36 @@ namespace Dashboard.OpenGL.Drawing
|
||||
public void Require(DeviceContext context)
|
||||
{
|
||||
Context = context;
|
||||
_dr = context.ExtensionRequire<IDirectRendering>();
|
||||
|
||||
_program = GL.CreateProgram();
|
||||
GlslShaderCreateInfo shader;
|
||||
|
||||
int vs = GL.CreateShader(ShaderType.VertexShader);
|
||||
|
||||
using (StreamReader reader = new StreamReader(GetType().Assembly
|
||||
using (StreamReader vertex = 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
|
||||
using (StreamReader fragment = new StreamReader(GetType().Assembly
|
||||
.GetManifestResourceStream("Dashboard.OpenGL.Drawing.immediate.frag")!))
|
||||
{
|
||||
GL.ShaderSource(fs, reader.ReadToEnd());
|
||||
shader = new GlslShaderCreateInfo()
|
||||
{
|
||||
VertexShader = vertex.ReadToEnd(),
|
||||
FragmentShader = fragment.ReadToEnd(),
|
||||
};
|
||||
}
|
||||
|
||||
GL.CompileShader(fs);
|
||||
GL.AttachShader(_program, fs);
|
||||
_program = (GLShader)_dr.CreateShader(shader);
|
||||
|
||||
GL.LinkProgram(_program);
|
||||
GL.DeleteShader(vs); GL.DeleteShader(fs);
|
||||
_program_apos = (uint)GL.GetAttribLocation(_program.Handle, "aPos");
|
||||
_program_atexcoord = (uint)GL.GetAttribLocation(_program.Handle, "aTexCoords");
|
||||
_program_acolor = (uint)GL.GetAttribLocation(_program.Handle, "aColor");
|
||||
|
||||
_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.Handle, "transforms");
|
||||
_program_image = GL.GetUniformLocation(_program.Handle, "image");
|
||||
|
||||
_program_transforms = GL.GetUniformLocation(_program, "transforms");
|
||||
_program_image = GL.GetUniformLocation(_program, "image");
|
||||
_white = (GLTexture)_dr.CreateTexture(TextureType.Texture2D);
|
||||
_white.SetStorage(PixelFormat.Rgb8I, 1, 1, 1, 1);
|
||||
|
||||
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.BindTexture(TextureTarget.Texture2D, _white.Handle);
|
||||
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, 1, 1, OpenTK.Graphics.OpenGL.PixelFormat.Rgb, PixelType.Byte, stackalloc byte[] { 0xFF, 0xFF, 0xFF, 0xFF });
|
||||
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);
|
||||
@@ -113,10 +111,10 @@ namespace Dashboard.OpenGL.Drawing
|
||||
|
||||
Matrix4x4 view = Context.ExtensionRequire<IDeviceContextBase>().Transforms;
|
||||
|
||||
GL.UseProgram(_program);
|
||||
GL.UseProgram(_program.Handle);
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
GL.BindTexture(TextureTarget.Texture2D, _white);
|
||||
GL.BindTexture(TextureTarget.Texture2D, _white.Handle);
|
||||
|
||||
GL.UniformMatrix4f(_program_transforms, 1, true, ref view);
|
||||
GL.Uniform1i(_program_image, 0);
|
||||
@@ -152,10 +150,10 @@ namespace Dashboard.OpenGL.Drawing
|
||||
|
||||
Matrix4x4 view = Context.ExtensionRequire<IDeviceContextBase>().Transforms;
|
||||
|
||||
GL.UseProgram(_program);
|
||||
GL.UseProgram(_program.Handle);
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
GL.BindTexture(TextureTarget.Texture2D, _white);
|
||||
GL.BindTexture(TextureTarget.Texture2D, _white.Handle);
|
||||
|
||||
GL.UniformMatrix4f(_program_transforms, 1, true, ref view);
|
||||
GL.Uniform1i(_program_image, 0);
|
||||
@@ -204,7 +202,7 @@ namespace Dashboard.OpenGL.Drawing
|
||||
GL.EnableVertexAttribArray(_program_acolor);
|
||||
Matrix4x4 view = Context.ExtensionRequire<IDeviceContextBase>().Transforms;
|
||||
|
||||
GL.UseProgram(_program);
|
||||
GL.UseProgram(_program.Handle);
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
GL.BindTexture(TextureTarget.Texture2D, ((GLTexture)texture).Handle);
|
||||
@@ -224,17 +222,53 @@ namespace Dashboard.OpenGL.Drawing
|
||||
Require((DeviceContext)context);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Pack = sizeof(float) * 4, Size = Size)]
|
||||
private struct ImmediateVertex(Vector3 position, Vector2 texCoords, Vector4 color)
|
||||
public void DrawImmediate(ImmediateDrawCall call)
|
||||
{
|
||||
[FieldOffset(PosOffset)] public Vector3 Position = position;
|
||||
[FieldOffset(TexCoordsOffset)] public Vector2 TexCoords = texCoords;
|
||||
[FieldOffset(ColorOffset)] public Vector4 Color = color;
|
||||
// This is a terrible implementation as it stands but we can improve this immensely later on.
|
||||
IDirectRendering dr = Context.ExtensionRequire<IDirectRendering>();
|
||||
|
||||
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);
|
||||
int size = call.Vertices.Length * ImmediateVertex.Size;
|
||||
|
||||
IBuffer buffer = dr.CreateBuffer(BufferAccessPattern.Stream, size);
|
||||
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();
|
||||
|
||||
ExtensionPreload<DeviceContextBase>();
|
||||
ExtensionPreload<GLTextureExtension>();
|
||||
ExtensionPreload<ImmediateMode>();
|
||||
ExtensionPreload<DirectRendering>();
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{9D6CCC74
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dashboard.TestApplication", "tests\Dashboard.TestApplication\Dashboard.TestApplication.csproj", "{7C90B90B-DF31-439B-9080-CD805383B014}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{1BDFEF50-C907-42C8-B63B-E4F6F585CFB5} = {1BDFEF50-C907-42C8-B63B-E4F6F585CFB5}
|
||||
{49A62F46-AC1C-4240-8615-020D4FBBF964} = {49A62F46-AC1C-4240-8615-020D4FBBF964}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
|
||||
@@ -74,64 +74,21 @@ TK.Window.SetMode(window.WindowHandle, WindowMode.Normal);
|
||||
window.DeviceContext.ExtensionRequire<IDeviceContextBase>().ScaleOverride = 1.5f;
|
||||
|
||||
IDirectRendering direct = window.DeviceContext.ExtensionRequire<IDirectRendering>();
|
||||
IBuffer vertex = direct.CreateBuffer(BufferAccessPattern.Static, 1024);
|
||||
float[] vertices = new float[]
|
||||
{ // x, y, z, _, r, g, b, a
|
||||
-0.5f, -0.5f, 0.0f, 0.0f, 1, 0, 0, 1,
|
||||
+0.5f, -0.5f, 0.0f, 0.0f, 0, 1, 0, 1,
|
||||
+0.0f, +0.5f, 0.0f, 0.0f, 0, 0, 1, 1,
|
||||
IImmediateMode imm = window.DeviceContext.ExtensionRequire<IImmediateMode>();
|
||||
ImmediateVertex[] vertices = new ImmediateVertex[]
|
||||
{ // x, y, z, r, g, b, a
|
||||
new ImmediateVertex(new System.Numerics.Vector3(-0.5f, -0.5f, 0.0f), System.Numerics.Vector2.Zero, new System.Numerics.Vector4(1, 0, 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)),
|
||||
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) =>
|
||||
{
|
||||
if (eventArgs is not PaintEventArgs paint)
|
||||
return;
|
||||
|
||||
paint.DeviceContext.ExtensionRequire<IDirectRendering>().Draw(call);
|
||||
imm.DrawImmediate(new ImmediateDrawCall(MeshPrimitive.Triangle, vertices.AsMemory()));
|
||||
};
|
||||
|
||||
app.Run(true, source.Token);
|
||||
|
||||
Reference in New Issue
Block a user