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 }; } }