91 lines
3.0 KiB
C#
91 lines
3.0 KiB
C#
using System.Reflection;
|
|
using System.Runtime.InteropServices;
|
|
using OpenTK.Graphics.OpenGL;
|
|
|
|
namespace Engine.Graphics.Buffer.Vertex;
|
|
|
|
/// <summary>
|
|
/// Interface for a vertex structure used in graphics buffers.
|
|
/// Provides methods for reflecting on vertex fields and checking their validity.
|
|
/// </summary>
|
|
public interface IVertex
|
|
{
|
|
/// <summary>
|
|
/// Retrieves the fields of a type implementing <see cref="IVertex"/>.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type to retrieve the fields for.</typeparam>
|
|
/// <returns>An ordered enumerable of <see cref="FieldInfo"/> for the fields in the type.</returns>
|
|
public static IOrderedEnumerable<FieldInfo> GetFields<T>()
|
|
{
|
|
return GetFields(typeof(T));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the fields of a specified type implementing <see cref="IVertex"/>.
|
|
/// </summary>
|
|
/// <param name="parType">The type to retrieve the fields for.</param>
|
|
/// <returns>An ordered enumerable of <see cref="FieldInfo"/> for the fields in the type.</returns>
|
|
public static IOrderedEnumerable<FieldInfo> GetFields(Type parType)
|
|
{
|
|
return parType.GetFields(BindingFlags.Public | BindingFlags.Instance).OrderBy(parF => parF.MetadataToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validates if a type is a valid <see cref="IVertex"/>.
|
|
/// Checks if all fields are value types, have <see cref="VertexAttribute"/> attributes, and match their size.
|
|
/// </summary>
|
|
/// <param name="parType">The type to validate.</param>
|
|
/// <returns>True if the type is valid, otherwise false.</returns>
|
|
public static bool IsValid(Type parType)
|
|
{
|
|
if (!parType.IsValueType || !parType.IsAssignableTo(typeof(IVertex)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var fields = GetFields(parType);
|
|
var totalSize = 0;
|
|
foreach (var field in fields)
|
|
{
|
|
if (!field.FieldType.IsValueType)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var attribute = field.GetCustomAttribute<VertexAttribute>();
|
|
if (attribute == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var size = AttributeSize(attribute.Type) * attribute.ComponentCount * attribute.RepeatCount;
|
|
if (size != Marshal.SizeOf(field.FieldType))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
totalSize += size;
|
|
}
|
|
|
|
return totalSize == Marshal.SizeOf(parType);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the size of a vertex attribute based on its OpenGL type.
|
|
/// </summary>
|
|
/// <param name="parType">The OpenGL type of the attribute.</param>
|
|
/// <returns>The size of the attribute in bytes.</returns>
|
|
public static int AttributeSize(VertexAttribType parType)
|
|
{
|
|
return parType switch
|
|
{
|
|
VertexAttribType.Byte or VertexAttribType.UnsignedByte => sizeof(byte),
|
|
VertexAttribType.Short or VertexAttribType.UnsignedShort => sizeof(short),
|
|
VertexAttribType.Int or VertexAttribType.UnsignedInt => sizeof(int),
|
|
VertexAttribType.HalfFloat => Marshal.SizeOf<Half>(),
|
|
VertexAttribType.Float => sizeof(float),
|
|
VertexAttribType.Double => sizeof(double),
|
|
_ => 0
|
|
};
|
|
}
|
|
} |