private static int ComputeAttributeStride(IEnumerable <VertexAttribute> attributes) { var stride = 0; foreach (var attr in attributes) { stride += VertexAttribute.GetSizeInBytes(attr.Type, attr.Size); } return(stride); }
internal static VertexAttribute[] GenerateAttributes(Type type) { // Get all fields w/ attribute defs var fields = type.GetFields() .Where(x => x.GetCustomAttribute <VertexAttributeAttribute>() != null) .ToArray(); // Must have at least one attribute defined if (fields.Length == 0) { throw new InvalidOperationException("Must have at least one field with a vertex attribute defined."); } // Console.WriteLine($"Attribute Layout: {type}"); // Create attribute list (one attributed per field) var attributes = new List <VertexAttribute>(); // For each field for (var f = 0; f < fields.Length; f++) { var attribute = fields[f].GetCustomAttribute <VertexAttributeAttribute>(); var field = fields[f]; // Number of attributes needed to describe this data, most attributes will be one. var attributeCount = GetAttributeCount(field.FieldType); // Get offset and usable size var nextOffset = f != (fields.Length - 1) ? OffsetOf(fields[f + 1]) : Marshal.SizeOf(type); var currOffset = OffsetOf(field); var size = nextOffset - currOffset; // Gather respective field type var attr = GetAttributeType(field.FieldType); var step = GetSizeInBytes(attr, 1) * attributeCount; var count = size / step; var waste = size % step; if (waste != 0) { throw new Exception($"Vertex attribute defined in struct has unattributed space after '{attr}'."); } // Store extracted attribute data for (var o = 0u; o < attributeCount; o++) { var _attribute = new VertexAttribute(attribute.Attribute, count, attr, attribute.Normalize, o); // Console.WriteLine($" {attribute.Attribute} ({_attribute.Index}): {count} x {attr}"); attributes.Add(_attribute); } } return(attributes.ToArray());