Replaced VBO with Buffer and SubArray. Program now recieves Buffer, rather than VBO receiving Program. Added VertexDataAttribute for vertex structs.

Split json files to test this functionality.
This commit is contained in:
2017-02-26 18:51:21 -05:00
parent 7500e0e7a4
commit 02a9a6d662
15 changed files with 346 additions and 119 deletions

47
Diamond/Buffers/Buffer.cs Normal file
View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using OpenTK.Graphics.OpenGL4;
namespace Diamond.Buffers
{
public class Buffer : GLObject
{
public readonly BufferTarget Target;
public readonly BufferUsageHint Usage;
public Buffer(BufferTarget target, BufferUsageHint usage = BufferUsageHint.StaticDraw)
: base((uint) GL.GenBuffer())
{
Target = target;
Usage = usage;
}
public void Bind()
{
GL.BindBuffer(Target, Id);
}
protected override void Delete()
{
GL.DeleteBuffer(Id);
}
public void Data<T>(T[] data) where T : struct
{
var size = Marshal.SizeOf<T>();
Bind();
GL.BufferData(Target, (IntPtr) (size * data.Length), data, Usage);
}
public void SubData<T>(SubArray<T> data) where T : struct
{
var size = Marshal.SizeOf<T>();
Bind();
GL.BufferSubData(Target, (IntPtr) (data.Offset * size), (IntPtr) (data.Length * size), data.Array);
}
}
}

105
Diamond/Buffers/SubArray.cs Normal file
View File

@@ -0,0 +1,105 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Linq;
using OpenTK.Graphics.ES20;
namespace Diamond.Buffers
{
public class SubArray<T> : IEnumerable<T>
{
public T[] Array;
public int Offset;
public int Length;
public T this[int i]
{
get
{
if (i < 0 || i >= Length)
throw new IndexOutOfRangeException("Index out of bounds of subarray");
return Array[i + Offset];
}
set
{
if (i < 0 || i >= Length)
throw new IndexOutOfRangeException("Index out of bounds of subarray.");
Array[i + Offset] = value;
}
}
public SubArray(T[] array) : this(array, 0, array.Length)
{
}
public SubArray(T[] array, int offset, int length)
{
Array = array;
Offset = offset;
Length = length;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
for (var i = 0; i < Length; i++)
yield return Array[Offset + i];
}
public static T[] Join<T>(params SubArray<T>[] subArrays) => Join((IEnumerable<SubArray<T>>) subArrays);
public static T[] Join<T>(IEnumerable<SubArray<T>> subArrays)
{
HashSet<T[]> uniqueArrays = new HashSet<T[]>();
foreach (var subArray in subArrays)
{
uniqueArrays.Add(subArray.Array);
}
if (uniqueArrays.Count == 0) return new T[0];
if (uniqueArrays.Count == 1) return uniqueArrays.ToArray()[0];
var length = 0;
var offsets = new Dictionary<T[], int>();
foreach (var uniqueArray in uniqueArrays)
{
offsets[uniqueArray] = length;
length += uniqueArray.Length;
}
var array = new T[length];
foreach (var uniqueArray in uniqueArrays)
{
System.Array.ConstrainedCopy(uniqueArray, 0, array, offsets[uniqueArray], uniqueArray.Length);
}
foreach (var subArray in subArrays)
{
subArray.Offset = offsets[subArray.Array];
subArray.Array = array;
}
return array;
}
public T[] ToArray()
{
var arr = new T[Length];
System.Array.ConstrainedCopy(Array, Offset, arr, 0, Length);
return arr;
}
public override string ToString()
{
if (Length == 0)
return "[ ]";
return $"[{string.Join(", ", this)}]";
}
}
}

View File

@@ -1,79 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Diamond.Shaders;
using OpenTK.Graphics.OpenGL4;
namespace Diamond.Buffers
{
public static class VBO
{
public static void Unbind()
{
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
}
}
public class VBO<T> : GLObject where T : struct
{
public VBO()
: base((uint) GL.GenBuffer())
{
}
protected override void Delete()
{
GL.DeleteBuffer(Id);
}
public void Bind()
{
GL.BindBuffer(BufferTarget.ArrayBuffer, Id);
}
public void Data(T[] data, BufferUsageHint usage = BufferUsageHint.StaticDraw)
{
Bind();
var size = Marshal.SizeOf(typeof(T));
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr) (size * data.Length), data, usage);
VBO.Unbind();
}
private static readonly int Stride;
private static readonly VertexPointerAttribute[] Attributes;
static VBO()
{
var attribList = new List<VertexPointerAttribute>();
Stride = Marshal.SizeOf(typeof(T));
foreach (var fieldInfo in typeof(T).GetFields())
{
var attrs = fieldInfo.GetCustomAttributes(typeof(VertexPointerAttribute), false);
if (attrs.Length == 0) continue;
var offset = (int) Marshal.OffsetOf(typeof(T), fieldInfo.Name);
foreach (var attr in attrs)
{
var vpa = (VertexPointerAttribute) attr;
vpa.Offset = offset;
attribList.Add(vpa);
}
}
Attributes = attribList.ToArray();
}
public void AttribPointers(Program pgm)
{
Bind();
foreach (var attr in Attributes)
{
if (!pgm.TryGetAttribute(attr.Name, out int loc)) continue;
GL.VertexAttribPointer(loc, attr.Size, attr.Type, attr.Normalized, Stride, attr.Offset);
GL.VertexAttribDivisor(loc, attr.Divisor);
}
VBO.Unbind();
}
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Diamond.Buffers
{
[AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
public sealed class VertexDataAttribute : Attribute
{
public VertexDataAttribute()
{
}
}
}

View File

@@ -44,13 +44,15 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Buffers\Buffer.cs" />
<Compile Include="Buffers\SubArray.cs" />
<Compile Include="Buffers\VertexDataAttribute.cs" />
<Compile Include="GLObject.cs" />
<Compile Include="Shaders\Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Shaders\Shader.cs" />
<Compile Include="Shaders\ShaderException.cs" />
<Compile Include="Textures\Texture.cs" />
<Compile Include="Buffers\VBO.cs" />
<Compile Include="Buffers\VertexPointerAttribute.cs" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,6 +1,10 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using Diamond.Buffers;
using OpenTK.Graphics.OpenGL4;
using Buffer = Diamond.Buffers.Buffer;
namespace Diamond.Shaders
{
@@ -84,6 +88,41 @@ namespace Diamond.Shaders
return id;
}
public void SetAttribPointers(Buffer buff, Type vertexType)
{
if (vertexType.GetCustomAttributes(typeof(VertexDataAttribute), false).Length == 0)
{
throw new ShaderException($"Cannot attach buffer {buff} to program {this}" +
$" with vertex {vertexType} because it has no" +
$" VertexData attribute.");
}
var attribList = new List<VertexPointerAttribute>();
var Stride = Marshal.SizeOf(vertexType);
foreach (var fieldInfo in vertexType.GetFields())
{
var attrs = fieldInfo.GetCustomAttributes(typeof(VertexPointerAttribute), false);
if (attrs.Length == 0) continue;
var offset = (int) Marshal.OffsetOf(vertexType, fieldInfo.Name);
foreach (var attr in attrs)
{
var vpa = (VertexPointerAttribute) attr;
vpa.Offset = offset;
attribList.Add(vpa);
}
}
buff.Bind();
foreach (var attr in attribList)
{
if (!TryGetAttribute(attr.Name, out int loc)) continue;
GL.VertexAttribPointer(loc, attr.Size, attr.Type, attr.Normalized, Stride, attr.Offset);
GL.VertexAttribDivisor(loc, attr.Divisor);
}
}
public void EnableAllAttribArrays()
{
foreach (var loc in attributes.Values)