3b20c53088
- 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.
275 lines
13 KiB
C#
275 lines
13 KiB
C#
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;
|
|
|
|
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 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 GLTexture _white;
|
|
|
|
public void Dispose()
|
|
{
|
|
}
|
|
|
|
public void Require(DeviceContext context)
|
|
{
|
|
Context = context;
|
|
_dr = context.ExtensionRequire<IDirectRendering>();
|
|
|
|
GlslShaderCreateInfo shader;
|
|
|
|
using (StreamReader vertex = new StreamReader(GetType().Assembly
|
|
.GetManifestResourceStream("Dashboard.OpenGL.Drawing.immediate.vert")!))
|
|
using (StreamReader fragment = new StreamReader(GetType().Assembly
|
|
.GetManifestResourceStream("Dashboard.OpenGL.Drawing.immediate.frag")!))
|
|
{
|
|
shader = new GlslShaderCreateInfo()
|
|
{
|
|
VertexShader = vertex.ReadToEnd(),
|
|
FragmentShader = fragment.ReadToEnd(),
|
|
};
|
|
}
|
|
|
|
_program = (GLShader)_dr.CreateShader(shader);
|
|
|
|
_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_transforms = GL.GetUniformLocation(_program.Handle, "transforms");
|
|
_program_image = GL.GetUniformLocation(_program.Handle, "image");
|
|
|
|
_white = (GLTexture)_dr.CreateTexture(TextureType.Texture2D);
|
|
_white.SetStorage(PixelFormat.Rgb8I, 1, 1, 1, 1);
|
|
|
|
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);
|
|
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);
|
|
|
|
Matrix4x4 view = Context.ExtensionRequire<IDeviceContextBase>().Transforms;
|
|
|
|
GL.UseProgram(_program.Handle);
|
|
|
|
GL.ActiveTexture(TextureUnit.Texture0);
|
|
GL.BindTexture(TextureTarget.Texture2D, _white.Handle);
|
|
|
|
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);
|
|
|
|
Matrix4x4 view = Context.ExtensionRequire<IDeviceContextBase>().Transforms;
|
|
|
|
GL.UseProgram(_program.Handle);
|
|
|
|
GL.ActiveTexture(TextureUnit.Texture0);
|
|
GL.BindTexture(TextureTarget.Texture2D, _white.Handle);
|
|
|
|
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(in RectangleDrawInfo rectangle)
|
|
{
|
|
// TODO: implement this better.
|
|
int z = Context.ExtensionRequire<IDeviceContextBase>().IncrementZ();
|
|
Color color = (rectangle.Fill as SolidColorBrush)?.Color ?? Color.LightGray;
|
|
Vector4 colorV = new Vector4(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f);
|
|
Vector4 margin = rectangle.Box.Margin;
|
|
Vector4 border = rectangle.Box.Border;
|
|
Vector2 size = rectangle.Box.Size + new Vector2(border.X + border.Z, border.Y = border.W);
|
|
Box2d box = Box2d.FromPositionAndSize(rectangle.Position + new Vector2(margin.X + border.X, margin.Y + border.Y), size);
|
|
|
|
Rectangle(box, z, colorV);
|
|
}
|
|
|
|
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);
|
|
Matrix4x4 view = Context.ExtensionRequire<IDeviceContextBase>().Transforms;
|
|
|
|
GL.UseProgram(_program.Handle);
|
|
|
|
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);
|
|
}
|
|
|
|
public void DrawImmediate(ImmediateDrawCall call)
|
|
{
|
|
// This is a terrible implementation as it stands but we can improve this immensely later on.
|
|
IDirectRendering dr = Context.ExtensionRequire<IDirectRendering>();
|
|
|
|
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
|
|
]
|
|
);
|
|
}
|
|
}
|
|
}
|