[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
public class VertexElementAttribute : Attribute
{
static Dictionary<Type, VertexElement[]> ms_elementCache = new Dictionary<Type, VertexElement[]>();
public static VertexElement[] GetVertexElements(Type vertexType)
{
if (!vertexType.IsValueType || vertexType.IsPrimitive || vertexType.IsEnum)
throw new ArgumentException("The type specified must be a structure.", "vertexType");
VertexElement[] vertexElements;
if (!ms_elementCache.TryGetValue(vertexType, out vertexElements))
{
FieldInfo[] fields = vertexType.GetFields(BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.NonPublic);
if (fields != null)
{
List<VertexElement> elementList = new List<VertexElement>();
for (int f = 0; f < fields.Length; f++)
{
object[] veAttribs = fields[f].GetCustomAttributes(typeof(VertexElementAttribute), false);
if (veAttribs == null || veAttribs.Length < 1)
continue;
VertexElementAttribute vertexAttrib = veAttribs[0] as VertexElementAttribute;
if (vertexAttrib == null)
continue;
VertexElement newElement = new VertexElement();
newElement.Name = vertexAttrib.Name;
newElement.Normalized = vertexAttrib.Normalized;
newElement.Type = vertexAttrib.DataType;
newElement.Size = vertexAttrib.Size;
newElement.Offset = Marshal.OffsetOf(vertexType, fields[f].Name);
elementList.Add(newElement);
}
if (elementList.Count > 0)
{
vertexElements = elementList.ToArray();
ms_elementCache.Add(vertexType, vertexElements);
}
}
}
VertexElement[] result = null;
if (vertexElements != null)
{
result = new VertexElement[vertexElements.Length];
Array.Copy(vertexElements, result, vertexElements.Length);
}
return result;
}
public static bool Apply(Type vertexType, ShaderProgram program, int stride = 0)
{
VertexElement[] vertexElements = GetVertexElements(vertexType);
if (vertexElements != null)
{
for (int i = 0; i < vertexElements.Length; i++)
{
vertexElements[i].Apply(program, stride);
}
return true;
}
return false;
}
public string Name { get; set; }
public VertexAttribPointerType DataType { get; set; }
public int Size { get; set; }
public bool Normalized { get; set; }
public VertexElementAttribute(string name, VertexAttribPointerType dataType, int size, bool normalized = false)
: base()
{
Name = name;
DataType = dataType;
Size = size;
Normalized = normalized;
}
}