using System.Reflection; using System.Runtime.InteropServices; using OpenTK.Graphics.OpenGL; namespace Engine.Renderer.Buffer.Vertex; public interface IVertex { public static IOrderedEnumerable GetFields() => GetFields(typeof(T)); public static IOrderedEnumerable GetFields(Type type) => type.GetFields(BindingFlags.Public | BindingFlags.Instance).OrderBy(f => f.MetadataToken); public static bool IsValid(Type type) { if (!type.IsValueType || !type.IsAssignableTo(typeof(IVertex))) return false; var fields = GetFields(type); 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(type); } public static int AttributeSize(VertexAttribType type) => type 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 }; }