Added documentation to VertexData, and VertexPointer, and VertexDataInfo

This commit is contained in:
2017-03-01 17:08:09 -05:00
parent af6d8b0e8a
commit 4979c59695
4 changed files with 147 additions and 84 deletions

View File

@@ -2,11 +2,22 @@
namespace Diamond.Buffers
{
/// <summary>
/// Marks a struct as vertex data that can be sent to a shader attribute
/// </summary>
[AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
public sealed class VertexDataAttribute : Attribute
{
/// <summary>
/// The pointer divisor for this type. A value of 0 indicates per-vertex, a value of 1+
/// indicates every n instances
/// </summary>
public int Divisor { get; set; } = 0;
/// <summary>
/// Mark a struct with information about how to iterate over vertex data of this type.
/// All fields of this struct must have [VertexPointer]
/// </summary>
public VertexDataAttribute()
{
}

View File

@@ -0,0 +1,127 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using Diamond.Shaders;
using OpenTK.Graphics.OpenGL4;
namespace Diamond.Buffers
{
/// <summary>
/// Get vertex pointer information about a struct to infer how to point shader attributes to it
/// </summary>
public class VertexDataInfo
{
/// <summary>
/// All shader attributes supported by this type
/// </summary>
public IReadOnlyCollection<VertexPointerAttribute> Pointers { get; }
/// <summary>
/// The size of this type in bytes
/// </summary>
public int Stride { get; }
/// <summary>
/// The pointer divisor for this type. A value of 0 indicates per-vertex, a value of 1+
/// indicates every n instances
/// </summary>
public readonly int Divisor;
/// <summary>
/// Create an info class with pre-computed values
/// </summary>
/// <param name="pointers">The type's supported attributes</param>
/// <param name="stride">The type's stride</param>
/// <param name="divisor">The type's pointer divisor</param>
private VertexDataInfo(IList<VertexPointerAttribute> pointers, int stride, int divisor)
{
Pointers = new ReadOnlyCollection<VertexPointerAttribute>(pointers);
Stride = stride;
Divisor = divisor;
}
/// <summary>
/// Enable the attributes associated with this type on Program.Current
/// </summary>
public void EnableVertexPointers()
{
if (Program.Current == null)
throw new InvalidOperationException("Cant render a mesh with no active shader.");
foreach (var attr in Pointers)
{
var loc = Program.Current.AttributeLocation(attr.Name);
if (!loc.HasValue)
continue;
GL.EnableVertexAttribArray((int) loc);
GL.VertexAttribDivisor((int) loc, Divisor);
}
}
/// <summary>
/// Disable the attributes associated with this type on Program.Current
/// </summary>
public void DisableVertexPointers()
{
if (Program.Current == null)
throw new InvalidOperationException("Cant render a mesh with no active shader.");
foreach (var attr in Pointers)
{
var loc = Program.Current.AttributeLocation(attr.Name);
if (!loc.HasValue)
continue;
GL.DisableVertexAttribArray((int) loc);
}
}
/// <summary>
/// A cache of already computed information to prevent redundant reflection calls
/// </summary>
private static readonly Dictionary<Type, VertexDataInfo> attribCache =
new Dictionary<Type, VertexDataInfo>();
/// <summary>
/// Get the VertexDataInfo for a particular type
/// </summary>
/// <typeparam name="T">The type to analyse</typeparam>
/// <returns>The VertexDataInfo for the type, or null if the type is not supported</returns>
public static VertexDataInfo GetInfo<T>() where T : struct
{
if (attribCache.ContainsKey(typeof(T))) return attribCache[typeof(T)];
var vertexDataAttributes = typeof(T).GetCustomAttributes(typeof(VertexDataAttribute), false);
// the type must have [VertexData]
if (vertexDataAttributes.Length != 1)
return null;
var vertdataattrib = (VertexDataAttribute) vertexDataAttributes[0];
var divisor = vertdataattrib.Divisor;
var attribList = new List<VertexPointerAttribute>();
var stride = Marshal.SizeOf<T>();
foreach (var fieldInfo in typeof(T).GetFields())
{
var attrs = fieldInfo.GetCustomAttributes(typeof(VertexPointerAttribute), false);
// all fields must have [VertexPointer]
if (attrs.Length == 0)
return null;
var offset = (int) Marshal.OffsetOf<T>(fieldInfo.Name);
foreach (var attr in attrs)
{
var vpa = (VertexPointerAttribute) attr;
vpa.Offset = offset;
attribList.Add(vpa);
}
}
return new VertexDataInfo(attribList, stride, divisor);
}
}
}

View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using Diamond.Shaders;
using OpenTK.Graphics.OpenGL4;
namespace Diamond.Buffers
@@ -40,91 +36,19 @@ namespace Diamond.Buffers
/// The offset of this attribute within each element
/// Corresponds to the <code>offset</code> parameter to <code>glVertexAttribPointer</code>
/// </summary>
public int Offset { get; set; } = 0;
// todo this, and other values, should be moved into a different type for use with VertexDataInfo.
// this class should just mark fields with their use - other types should manage binding those fields
public int Offset { get; internal set; } = 0;
/// <summary>
/// Mark a field with information about how to point a shader attribute to it
/// </summary>
/// <param name="name">The name of the attribute to point to this</param>
/// <param name="size">The number of elements to read from this field</param>
public VertexPointerAttribute(string name, int size)
{
Name = name;
Size = size;
}
}
public class VertexDataInfo
{
public readonly IReadOnlyCollection<VertexPointerAttribute> Pointers;
public readonly int Stride;
public readonly int Divisor;
private VertexDataInfo(IList<VertexPointerAttribute> pointers, int stride, int divisor)
{
Pointers = new ReadOnlyCollection<VertexPointerAttribute>(pointers);
Stride = stride;
Divisor = divisor;
}
public void EnableVertexPointers()
{
if (Program.Current == null)
throw new InvalidOperationException("Cant render a mesh with no active shader.");
foreach (var attr in Pointers)
{
var loc = Program.Current.AttributeLocation(attr.Name);
if (!loc.HasValue)
continue;
GL.EnableVertexAttribArray((int) loc);
GL.VertexAttribDivisor((int) loc, Divisor);
}
}
public void DisableVertexPointers()
{
if (Program.Current == null)
throw new InvalidOperationException("Cant render a mesh with no active shader.");
foreach (var attr in Pointers)
{
var loc = Program.Current.AttributeLocation(attr.Name);
if (!loc.HasValue)
continue;
GL.DisableVertexAttribArray((int) loc);
}
}
private static readonly Dictionary<Type, VertexDataInfo> attribCache =
new Dictionary<Type, VertexDataInfo>();
public static VertexDataInfo GetInfo<T>() where T : struct
{
if (attribCache.ContainsKey(typeof(T))) return attribCache[typeof(T)];
var vertexDataAttributes = typeof(T).GetCustomAttributes(typeof(VertexDataAttribute), false);
if (vertexDataAttributes.Length != 1)
return null;
var vertdataattrib = (VertexDataAttribute) vertexDataAttributes[0];
var divisor = vertdataattrib.Divisor;
var attribList = new List<VertexPointerAttribute>();
var stride = Marshal.SizeOf<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<T>(fieldInfo.Name);
foreach (var attr in attrs)
{
var vpa = (VertexPointerAttribute) attr;
vpa.Offset = offset;
attribList.Add(vpa);
}
}
return new VertexDataInfo(attribList, stride, divisor);
}
}
}

View File

@@ -52,6 +52,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Buffers\Buffer.cs" />
<Compile Include="Buffers\VertexDataInfo.cs" />
<Compile Include="Wrappers\BufferWrap.cs" />
<Compile Include="GLObject.cs" />
<Compile Include="Wrappers\ProgramWrap.cs" />