using System.Reflection;
using System.Runtime.InteropServices;
using OpenTK.Graphics.OpenGL;
namespace Engine.Graphics.Buffer.Vertex;
///
/// Interface for a vertex structure used in graphics buffers.
/// Provides methods for reflecting on vertex fields and checking their validity.
///
public interface IVertex
{
///
/// Retrieves the fields of a type implementing .
///
/// The type to retrieve the fields for.
/// An ordered enumerable of for the fields in the type.
public static IOrderedEnumerable GetFields()
{
return GetFields(typeof(T));
}
///
/// Retrieves the fields of a specified type implementing .
///
/// The type to retrieve the fields for.
/// An ordered enumerable of for the fields in the type.
public static IOrderedEnumerable GetFields(Type parType)
{
return parType.GetFields(BindingFlags.Public | BindingFlags.Instance).OrderBy(parF => parF.MetadataToken);
}
///
/// Validates if a type is a valid .
/// Checks if all fields are value types, have attributes, and match their size.
///
/// The type to validate.
/// True if the type is valid, otherwise false.
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();
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);
}
///
/// Gets the size of a vertex attribute based on its OpenGL type.
///
/// The OpenGL type of the attribute.
/// The size of the attribute in bytes.
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(),
VertexAttribType.Float => sizeof(float),
VertexAttribType.Double => sizeof(double),
_ => 0
};
}
}