-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* 🚧 Make renderable construction more flexible * 🔢 Allow instanced vertex data * 🐛 Update examples * 🔒 Enforce index buffer type
- Loading branch information
1 parent
d5acd25
commit 5f3cd72
Showing
15 changed files
with
347 additions
and
230 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using Bearded.Graphics.Vertices; | ||
|
||
namespace Bearded.Graphics.Rendering; | ||
|
||
public static class BufferExtensions | ||
{ | ||
public static IVertexBuffer AsVertexBuffer<TVertex>(this Buffer<TVertex> buffer) | ||
where TVertex : struct, IVertexData | ||
{ | ||
return VertexBuffer.From(buffer); | ||
} | ||
|
||
public static IVertexBuffer AsVertexBuffer<TVertex>(this BufferStream<TVertex> buffer) | ||
where TVertex : struct, IVertexData | ||
{ | ||
return VertexBuffer.From(buffer); | ||
} | ||
|
||
public static IIndexBuffer AsIndexBuffer(this Buffer<byte> buffer) => IndexBuffer.From(buffer); | ||
public static IIndexBuffer AsIndexBuffer(this Buffer<ushort> buffer) => IndexBuffer.From(buffer); | ||
public static IIndexBuffer AsIndexBuffer(this Buffer<uint> buffer) => IndexBuffer.From(buffer); | ||
public static IIndexBuffer AsIndexBuffer(this BufferStream<byte> buffer) => IndexBuffer.From(buffer); | ||
public static IIndexBuffer AsIndexBuffer(this BufferStream<ushort> buffer) => IndexBuffer.From(buffer); | ||
public static IIndexBuffer AsIndexBuffer(this BufferStream<uint> buffer) => IndexBuffer.From(buffer); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
namespace Bearded.Graphics.Rendering; | ||
|
||
public interface IFlushableBuffer | ||
{ | ||
void FlushIfNeeded(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
using System; | ||
using OpenTK.Graphics.OpenGL; | ||
|
||
namespace Bearded.Graphics.Rendering; | ||
|
||
public interface IIndexBuffer | ||
{ | ||
int Count { get; } | ||
DrawElementsType ElementType { get; } | ||
void ConfigureBoundVertexArray(); | ||
} | ||
|
||
public static class IndexBuffer | ||
{ | ||
public static IIndexBuffer From(Buffer<byte> buffer) => new Static<byte>(buffer); | ||
public static IIndexBuffer From(Buffer<ushort> buffer) => new Static<ushort>(buffer); | ||
public static IIndexBuffer From(Buffer<uint> buffer) => new Static<uint>(buffer); | ||
|
||
public static IIndexBuffer From(BufferStream<byte> stream) => new Streaming<byte>(stream); | ||
public static IIndexBuffer From(BufferStream<ushort> stream) => new Streaming<ushort>(stream); | ||
public static IIndexBuffer From(BufferStream<uint> stream) => new Streaming<uint>(stream); | ||
|
||
private sealed class Static<TIndex>(Buffer<TIndex> buffer) : IIndexBuffer | ||
where TIndex : struct | ||
{ | ||
public int Count => buffer.Count; | ||
|
||
public DrawElementsType ElementType { get; } = elementType<TIndex>(); | ||
|
||
public void ConfigureBoundVertexArray() => buffer.Bind(BufferTarget.ElementArrayBuffer); | ||
} | ||
|
||
private sealed class Streaming<TIndex>(BufferStream<TIndex> stream) : IIndexBuffer, IFlushableBuffer | ||
where TIndex : struct | ||
{ | ||
public int Count => stream.Count; | ||
|
||
public DrawElementsType ElementType { get; } = elementType<TIndex>(); | ||
|
||
public void ConfigureBoundVertexArray() => stream.Buffer.Bind(BufferTarget.ElementArrayBuffer); | ||
|
||
public void FlushIfNeeded() => stream.FlushIfDirty(); | ||
} | ||
|
||
private static DrawElementsType elementType<TIndex>() | ||
{ | ||
return default(TIndex) switch | ||
{ | ||
byte => DrawElementsType.UnsignedByte, | ||
ushort => DrawElementsType.UnsignedShort, | ||
uint => DrawElementsType.UnsignedInt, | ||
_ => throw new NotSupportedException("Index type must be one of [byte, ushort, uint].") | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.Linq; | ||
using Bearded.Graphics.Shading; | ||
using OpenTK.Graphics.OpenGL; | ||
|
||
namespace Bearded.Graphics.Rendering; | ||
|
||
public static partial class Renderable | ||
{ | ||
public static IRenderable Build(PrimitiveType primitiveType, Action<Builder> configure) | ||
{ | ||
var builder = new Builder(primitiveType); | ||
configure(builder); | ||
return builder.Build(); | ||
} | ||
|
||
public sealed class Builder(PrimitiveType primitiveType) | ||
{ | ||
private readonly List<IVertexBuffer> vertexBuffers = []; | ||
private IIndexBuffer? indexBuffer; | ||
private Func<int>? instanceCount; | ||
|
||
public Builder With(IVertexBuffer buffer) | ||
{ | ||
vertexBuffers.Add(buffer); | ||
return this; | ||
} | ||
|
||
public Builder With(params IVertexBuffer[] buffers) | ||
{ | ||
vertexBuffers.AddRange(buffers); | ||
return this; | ||
} | ||
|
||
public Builder With(ReadOnlySpan<IVertexBuffer> buffers) | ||
{ | ||
vertexBuffers.AddRange(buffers); | ||
return this; | ||
} | ||
|
||
public Builder With(IEnumerable<IVertexBuffer> buffers) | ||
{ | ||
vertexBuffers.AddRange(buffers); | ||
return this; | ||
} | ||
|
||
public Builder With(IIndexBuffer buffer) | ||
{ | ||
indexBuffer = buffer; | ||
return this; | ||
} | ||
|
||
public Builder InstancedWith(Func<int> getInstanceCount) | ||
{ | ||
instanceCount = getInstanceCount; | ||
return this; | ||
} | ||
|
||
public IRenderable Build() | ||
{ | ||
if (vertexBuffers.Count == 0) | ||
throw new InvalidOperationException("Renderable must have at least one vertex buffer."); | ||
|
||
return build(primitiveType, [..vertexBuffers], indexBuffer, instanceCount); | ||
} | ||
|
||
private static IRenderable build( | ||
PrimitiveType type, | ||
ImmutableArray<IVertexBuffer> vertices, | ||
IIndexBuffer? indices, | ||
Func<int>? instanceCount) | ||
{ | ||
var flushables = listFlushableBuffers(vertices, indices); | ||
|
||
Action draw = (indices, instanceCount) switch | ||
{ | ||
(null, null) => () => GL.DrawArrays(type, 0, vertices[0].Count), | ||
(null, not null) => () => GL.DrawArraysInstanced(type, 0, vertices[0].Count, instanceCount()), | ||
(not null, null) => () => GL.DrawElements(type, indices.Count, indices.ElementType, 0), | ||
(not null, not null) => () => GL.DrawElementsInstanced(type, indices.Count, indices.ElementType, 0, instanceCount()), | ||
}; | ||
|
||
return new Implementation(configure, flushables.IsDefaultOrEmpty ? draw : flushAndDraw); | ||
|
||
void configure(ShaderProgram program) | ||
{ | ||
foreach (var buffer in vertices) | ||
{ | ||
buffer.ConfigureBoundVertexArray(program); | ||
} | ||
|
||
indices?.ConfigureBoundVertexArray(); | ||
} | ||
|
||
void flushAndDraw() | ||
{ | ||
foreach (var flushable in flushables) | ||
{ | ||
flushable.FlushIfNeeded(); | ||
} | ||
|
||
draw(); | ||
} | ||
|
||
} | ||
|
||
private static ImmutableArray<IFlushableBuffer> listFlushableBuffers( | ||
ImmutableArray<IVertexBuffer> vertices, IIndexBuffer? indices) | ||
{ | ||
var flushableCount = vertices.Count(b => b is IFlushableBuffer); | ||
flushableCount += indices is IFlushableBuffer ? 1 : 0; | ||
|
||
if (flushableCount == 0) | ||
return ImmutableArray<IFlushableBuffer>.Empty; | ||
|
||
var builder = ImmutableArray.CreateBuilder<IFlushableBuffer>(flushableCount); | ||
|
||
foreach (var buffer in vertices) | ||
{ | ||
if (buffer is IFlushableBuffer flushable) | ||
{ | ||
builder.Add(flushable); | ||
} | ||
} | ||
if (indices is IFlushableBuffer indexFlushable) | ||
{ | ||
builder.Add(indexFlushable); | ||
} | ||
|
||
return builder.MoveToImmutable(); | ||
} | ||
} | ||
|
||
private sealed class Implementation(Action<ShaderProgram> configureBoundVertexArray, Action render) : IRenderable | ||
{ | ||
public DrawCall MakeDrawCallFor(ShaderProgram program) | ||
{ | ||
return DrawCall.With(() => configureBoundVertexArray(program), render); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.