Skip to content

Commit

Permalink
Mesh abstraction
Browse files Browse the repository at this point in the history
  • Loading branch information
frederikja163 committed Apr 5, 2024
1 parent 9110a03 commit 9bb894f
Show file tree
Hide file tree
Showing 7 changed files with 254 additions and 45 deletions.
186 changes: 170 additions & 16 deletions JAngine/Rendering/Mesh.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,180 @@ public ShaderAttributeAttribute(string nameInShader)
public sealed class Mesh: IDisposable
{
private readonly List<VertexArray> _vaos;
private readonly Dictionary<Type, (IBuffer buffer, int divisor)> _buffers;
private readonly IBuffer<uint> _ebo;
private readonly Dictionary<Type, IBuffer> _vertexBuffers;
private readonly Dictionary<Type, IBuffer> _instanceBuffers;
private readonly Buffer<uint> _ebo;

public Mesh(Window window, string name, IBuffer<uint> indexBuffer)
public Mesh(Window window, string name)
{
Window = window;
Name = name;
_vaos = new List<VertexArray>();
_ebo = indexBuffer;
_buffers = new Dictionary<Type, (IBuffer buffer, int divisor)>(TypeComparer.Default);
_ebo = new Buffer<uint>(window, $"{name}.buffer");
_vertexBuffers = new Dictionary<Type, IBuffer>(TypeComparer.Default);
_instanceBuffers = new Dictionary<Type, IBuffer>();
}

public Window Window { get; }
public string Name { get; }

public void AddAttribute<T>(int divisor = 0, params T[] data) where T : unmanaged
public void AddIndices(ReadOnlySpan<uint> indices)
{
if (_buffers.TryGetValue(typeof(T), out (IBuffer buffer, int divisor) tuple))
_ebo.Add(indices);
}

public void AddIndex(uint index)
{
_ebo.Add(index);
}

public IEnumerable<uint> GetIndices()
{
return _ebo.ToList();
}

public void ClearIndices()
{
Span<uint> s = stackalloc uint[_ebo.Count];
s.Fill(0);
_ebo.SetSubData(0, s);
}

public void AddVertexAttribute<T>() where T : unmanaged
{
if (_vertexBuffers.TryGetValue(typeof(T), out IBuffer? buffer))
{
throw new Exception($"Mesh {Name} already contains a vertex attribute for {typeof(T).FullName}");
}
buffer = new Buffer<T>(Window, $"{Name}.vbuffer");
_vertexBuffers.Add(typeof(T), buffer);

foreach (VertexArray vao in _vaos)
{
AddAttributes(vao, buffer, 0);
}
}

private Buffer<T> GetVertexBuffer<T>() where T : unmanaged
{
if (!_vertexBuffers.TryGetValue(typeof(T), out IBuffer? buffer))
{
throw new Exception($"Mesh {Name} contains no vertex attribute for {typeof(T).FullName}");
}

Buffer<T> buf = (Buffer<T>)buffer;
return buf;
}

public BufferDataReference<T> AddVertex<T>(T data)
where T : unmanaged
{
Buffer<T> buf = GetVertexBuffer<T>();
return new BufferDataReference<T>(buf, buf.Add(data));
}

public IEnumerable<BufferDataReference<T>> AddVertices<T>(ReadOnlySpan<T> datas)
where T : unmanaged
{
Buffer<T> buf = GetVertexBuffer<T>();
int index = buf.Add(datas);
List<BufferDataReference<T>> references = new ();
foreach (T d in datas)
{
references.Add(new BufferDataReference<T>(buf, index++));
}

return references;
}

public BufferDataReference<T> GetVertex<T>(int index)
where T : unmanaged
{
Buffer<T> buf = GetVertexBuffer<T>();
return new BufferDataReference<T>(buf, index);
}

public IEnumerable<BufferDataReference<T>> GetVertices<T>(int start = 0, int count = -1)
where T : unmanaged
{
Buffer<T> buf = GetVertexBuffer<T>();
if (count == -1)
{
throw new Exception($"Mesh {Name} already contains an attribute for {typeof(T).FullName}");
count = buf.Count;
}
tuple.buffer = new Buffer<T>(Window, $"{Name}.buffer");
tuple.divisor = divisor;
_buffers.Add(typeof(T), tuple);

for (int i = start; i < start + count; i++)
{
yield return new BufferDataReference<T>(buf, i);
}
}

public void AddInstanceAttribute<T>() where T : unmanaged
{
if (_instanceBuffers.TryGetValue(typeof(T), out IBuffer? buffer))
{
throw new Exception($"Mesh {Name} already contains an instance attribute for {typeof(T).FullName}");
}
buffer = new Buffer<T>(Window, $"{Name}.ibuffer");
_instanceBuffers.Add(typeof(T), buffer);

foreach (VertexArray vao in _vaos)
{
AddAttributes(vao, tuple.buffer, tuple.divisor);
AddAttributes(vao, buffer, 1);
}
}

private Buffer<T> GetInstanceBuffer<T>() where T : unmanaged
{
if (!_instanceBuffers.TryGetValue(typeof(T), out IBuffer? buffer))
{
throw new Exception($"Mesh {Name} contains no instance attribute for {typeof(T).FullName}");
}

Buffer<T> buf = (Buffer<T>)buffer;
return buf;
}

public BufferDataReference<T> AddInstance<T>(T data)
where T : unmanaged
{
Buffer<T> buf = GetInstanceBuffer<T>();
return new BufferDataReference<T>(buf, buf.Add(data));
}

public IEnumerable<BufferDataReference<T>> AddInstances<T>(ReadOnlySpan<T> datas)
where T : unmanaged
{
Buffer<T> buf = GetInstanceBuffer<T>();
int index = buf.Add(datas);
List<BufferDataReference<T>> references = new ();
foreach (T d in datas)
{
references.Add(new BufferDataReference<T>(buf, index++));
}

return references;
}

public BufferDataReference<T> GetInstance<T>(int index)
where T : unmanaged
{
Buffer<T> buf = GetInstanceBuffer<T>();
return new BufferDataReference<T>(buf, index);
}

public IEnumerable<BufferDataReference<T>> GetInstances<T>(int start = 0, int count = -1)
where T : unmanaged
{
Buffer<T> buf = GetInstanceBuffer<T>();
if (count == -1)
{
count = buf.Count;
}

for (int i = start; i < start + count; i++)
{
yield return new BufferDataReference<T>(buf, i);
}
}

Expand All @@ -53,9 +199,13 @@ public void BindToShader(Shader shader)
VertexArray vao = new VertexArray(Window, Name + ".vao", shader, _ebo);
_vaos.Add(vao);

foreach ((IBuffer buffer, int divisor) in _buffers.Values)
foreach (IBuffer buffer in _vertexBuffers.Values)
{
AddAttributes(vao, buffer, divisor);
AddAttributes(vao, buffer, 0);
}
foreach (IBuffer buffer in _instanceBuffers.Values)
{
AddAttributes(vao, buffer, 1);
}
}

Expand All @@ -65,7 +215,7 @@ private static void AddAttributes(VertexArray vao, IBuffer buffer, int divisor)

foreach (FieldInfo field in buffer.UnderlyingType.GetRuntimeFields())
{
if (!Mesh.CsTypesToAttributes.TryGetValue(field.FieldType,
if (!CsTypesToAttributes.TryGetValue(field.FieldType,
out (int attributeCount, int count, Type type) tuple))
{
throw new Exception(
Expand All @@ -90,7 +240,11 @@ private static void AddAttributes(VertexArray vao, IBuffer buffer, int divisor)
public void Dispose()
{
_ebo.Dispose();
foreach ((IBuffer buffer, _) in _buffers.Values)
foreach (IBuffer buffer in _vertexBuffers.Values)
{
buffer.Dispose();
}
foreach (IBuffer buffer in _instanceBuffers.Values)
{
buffer.Dispose();
}
Expand Down
37 changes: 34 additions & 3 deletions JAngine/Rendering/OpenGL/Buffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ public void EnsureCapacity(int size)
{
capacity *= 2;
}

T[] oldData = _data;
_data = new T[capacity];
Array.Copy(oldData, _data, oldData.Length);
if (!_window.ReplaceUpdateUnique(this, UpdateDataEvent.SkipInstance))
{
_window.QueueUpdateUnique(this, UpdateDataEvent.SkipInstance);
Expand All @@ -71,10 +74,15 @@ public T this[Index index]

public Span<T> this[Range range] => _data[range];

public void SetSubData(int offset, params T[] data)
public void SetSubData(int offset, T data)
{
SetSubData(offset, stackalloc T[1]{data});
}

public void SetSubData(int offset, ReadOnlySpan<T> data)
{
EnsureCapacity(offset + data.Length);
Array.Copy(data, 0, _data, offset, data.Length);
Array.Copy(data.ToArray(), 0, _data, offset, data.Length);
int lastIndex = offset + data.Length;
if (Count < lastIndex)
{
Expand All @@ -86,6 +94,29 @@ public void SetSubData(int offset, params T[] data)
_window.QueueUpdateUnique(this, UpdateDataEvent.Default);
}

public int Add(T value)
{
int index = Count;
EnsureCapacity(index + 1);
SetSubData(index, value);
return index;
}

public int Add(ReadOnlySpan<T> value)
{
int index = Count;
EnsureCapacity(index + value.Length);
SetSubData(index, value);
return index;
}

public void Clear()
{
Array.Clear(_data);
_window.ReplaceUpdateUnique(this, UpdateDataEvent.SkipInstance);
_window.QueueUpdateUnique(this, UpdateCapacityEvent.Singleton);
}

public int FindIndex(T value)
{
for (var i = 0; i < _data.Length; i++)
Expand Down Expand Up @@ -126,7 +157,7 @@ unsafe void IGlObject.DispatchEvent(IGlEvent glEvent)
}

Gl.NamedBufferSubData<T>(_handle, (IntPtr)_firstUpdateIndex * sizeof(T),
(IntPtr)(_firstUpdateIndex - _lastUpdateIndex) * sizeof(T), ref _data[_firstUpdateIndex]);
(IntPtr)(_lastUpdateIndex - _firstUpdateIndex) * sizeof(T), ref _data[_firstUpdateIndex]);
(_firstUpdateIndex, _lastUpdateIndex) = (_data.Length - 1, 0);
break;
case DisposeEvent:
Expand Down
2 changes: 2 additions & 0 deletions JAngine/Rendering/OpenGL/BufferBinding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ internal event Action? OnChange
_onAction -= value;
}
}

internal bool IsQueued { get; set; }

public BufferBinding AddAttribute(string attributeName, int count, int divisor = 0)
{
Expand Down
16 changes: 16 additions & 0 deletions JAngine/Rendering/OpenGL/BufferDataReference.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace JAngine.Rendering.OpenGL;

public sealed class BufferDataReference<T>
where T : unmanaged
{
private readonly IBuffer<T> _buffer;

public BufferDataReference(IBuffer<T> buffer, int index)
{
_buffer = buffer;
Index = index;
}

public int Index { get; }
public T Data { get => _buffer[Index]; set => _buffer.SetSubData(Index, value); }
}
8 changes: 6 additions & 2 deletions JAngine/Rendering/OpenGL/IBuffer.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Collections;

namespace JAngine.Rendering.OpenGL;

public interface IBuffer: IGlObject, IDisposable
public interface IBuffer: IGlObject, IEnumerable, IDisposable
{
public Type UnderlyingType { get; }
public int Capacity { get; }
Expand All @@ -14,7 +16,9 @@ public interface IBuffer<T> : IBuffer, IEnumerable<T>
Type IBuffer.UnderlyingType => typeof(T);
public T this[Index index] { get; set; }
public Span<T> this[Range range] { get; }
public void SetSubData(int offset, params T[] data);
public void SetSubData(int offset, T data);
public void SetSubData(int offset, ReadOnlySpan<T> data);
public void Clear();
public int FindIndex(T value);
}

Expand Down
7 changes: 7 additions & 0 deletions JAngine/Rendering/OpenGL/VertexArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ public BufferBinding BindBuffer(IBuffer buffer, int offset = 0)

private void UpdateBinding(BufferBinding binding)
{
if (binding.IsQueued)
{
return;
}

binding.IsQueued = true;
_window.QueueUpdate(this, binding);
}

Expand All @@ -55,6 +61,7 @@ void IGlObject.DispatchEvent(IGlEvent glEvent)
Gl.VertexArrayElementBuffer(_handle, _ebo.Handle);
break;
case BufferBinding binding:
binding.IsQueued = false;
uint relativeOffset = 0;
foreach (BufferBinding.Attribute attribute in binding.GetAttributes())
{
Expand Down
Loading

0 comments on commit 9bb894f

Please sign in to comment.