public static void Validate(this IG3D g3d) { // Check that no attributes are null var n = g3d.Attributes.Count(attr => attr == null); if (n > 0) { throw new Exception("Attributes cannot be null"); } // Assure that there are no duplicates g3d.Attributes.ToDictionary(); // Validate the descriptors foreach (var attr in g3d.Attributes) { attr.Descriptor.Validate(); } // Compute the number of faces var faceCount = g3d.FaceCount(); // Assure that there is a vertex attribute if (g3d.VertexAttribute.Descriptor.Association != Association.assoc_vertex) { throw new Exception("Vertex buffer is not associated with vertex: " + g3d.VertexAttribute.Descriptor); } if (g3d.VertexAttribute.Descriptor.DataArity != 3) { throw new Exception("Vertices should have an arity of 3"); } if (g3d.Attributes(AttributeType.attr_vertex).Count() > 1) { throw new Exception("There can only be one vertex data set"); } // Compute the number of vertices var vertexCount = g3d.VertexCount(); // Computes the number of corners var cornerCount = g3d.CornerVertexIndices().Count; // Compute the number of groups. Groups requires the precense of a GroupIndex attribute var groupCount = g3d.GroupIndexAttributes().FirstOrDefault()?.Count ?? -1; // Compute the number of instance. The first instance channel determines the number of instances var instanceCount = g3d.Attributes(Association.assoc_instance).FirstOrDefault()?.Count ?? -1; // Check the number of items in each attribute foreach (var attr in g3d.Attributes) { switch (attr.Descriptor.Association) { case Association.assoc_vertex: if (attr.Count != vertexCount) { throw new Exception($"Attribute {attr.Descriptor} has {attr.Count} items, expected {vertexCount}"); } break; case Association.assoc_face: if (attr.Count != faceCount) { throw new Exception($"Attribute {attr.Descriptor} has {attr.Count} items, expected {faceCount}"); } break; case Association.assoc_corner: if (attr.Count != cornerCount) { throw new Exception($"Attribute {attr.Descriptor} has {attr.Count} items, expected {cornerCount}"); } break; case Association.assoc_edge: if (attr.Count != cornerCount) { throw new Exception($"Attribute {attr.Descriptor} has {attr.Count} items, expected {cornerCount}"); } break; case Association.assoc_object: if (attr.Count != 1) { throw new Exception($"Attribute {attr.Descriptor} has {attr.Count} items, expected 1"); } break; case Association.assoc_group: if (attr.Count != groupCount) { throw new Exception($"Attribute {attr.Descriptor} has {attr.Count} items, expected {groupCount}"); } break; case Association.assoc_instance: if (attr.Count != instanceCount) { throw new Exception($"Attribute {attr.Descriptor} has {attr.Count} items, expected {instanceCount}"); } break; case Association.assoc_none: break; default: throw new Exception($"Attribute {attr.Descriptor} has invalid association"); } } // The following rules are stricter than absolutely necessary, but respecting them // will make coding geometry libraries easier to write on top of the thing. g3d.Attributes(AttributeType.attr_binormal).ToList() .ValidateDataType(DataType.dt_float32) .ValidateArity(3) .ValidateAssociation(Association.assoc_vertex); g3d.Attributes(AttributeType.attr_tangent).ToList() .ValidateDataType(DataType.dt_float32) .ValidateArity(3) .ValidateAssociation(Association.assoc_vertex); g3d.Attributes(AttributeType.attr_normal).ToList() .ValidateDataType(DataType.dt_float32) .ValidateArity(3) .ValidateAssociation(Association.assoc_face, Association.assoc_corner, Association.assoc_vertex); g3d.Attributes(AttributeType.attr_color).ToList() .ValidateArity(1, 3, 4) .ValidateAssociation(Association.assoc_face, Association.assoc_corner, Association.assoc_vertex, Association.assoc_object); g3d.Attributes(AttributeType.attr_visibility).ToList() .ValidateArity(1) .ValidateDataType(DataType.dt_int8, DataType.dt_int32, DataType.dt_float32); g3d.Attributes(AttributeType.attr_faceindex).ToList() .ValidateArity(1) .ValidateDataType(DataType.dt_int32) .ValidateAssociation(Association.assoc_face) .ValidateMaxOne(); g3d.Attributes(AttributeType.attr_facesize).ToList() .ValidateArity(1) .ValidateDataType(DataType.dt_int32) .ValidateAssociation(Association.assoc_face, Association.assoc_object) .ValidateMaxOne(); g3d.Attributes(AttributeType.attr_index).ToList() .ValidateArity(1) .ValidateDataType(DataType.dt_int32) .ValidateAssociation(Association.assoc_corner) .ValidateMaxOne(); g3d.Attributes(AttributeType.attr_uv).ToList() .ValidateArity(2, 3) .ValidateDataType(DataType.dt_float32) .ValidateAssociation(Association.assoc_vertex, Association.assoc_corner); g3d.Attributes(AttributeType.attr_invalid).ToList() .ValidateNone(); g3d.Attributes(AttributeType.attr_index).ToList() .ValidateArity(1) .ValidateDataType(DataType.dt_int32) .ValidateAssociation(Association.assoc_corner) .ValidateMaxOne(); g3d.Attributes(AttributeType.attr_mapchannel_data).ToList() .ValidateArity(3) .ValidateDataType(DataType.dt_float32) .ValidateAssociation(Association.assoc_none); g3d.Attributes(AttributeType.attr_mapchannel_index).ToList() .ValidateArity(1) .ValidateDataType(DataType.dt_int32) .ValidateAssociation(Association.assoc_corner); g3d.Attributes(AttributeType.attr_materialid).ToList() .ValidateArity(1) .ValidateDataType(DataType.dt_int32) .ValidateAssociation(Association.assoc_face); g3d.Attributes(AttributeType.attr_pervertex).ToList() .ValidateArity(1) .ValidateDataType(DataType.dt_float32) .ValidateAssociation(Association.assoc_vertex); g3d.Attributes(AttributeType.attr_polygroup).ToList() .ValidateArity(1) .ValidateDataType(DataType.dt_int32) .ValidateAssociation(Association.assoc_face); g3d.Attributes(AttributeType.attr_smoothing).ToList() .ValidateArity(1) .ValidateDataType(DataType.dt_int32) .ValidateAssociation(Association.assoc_face); g3d.Attributes(AttributeType.attr_instance_transform).ToList() .ValidateArity(16) .ValidateDataType(DataType.dt_float32) .ValidateAssociation(Association.assoc_instance); g3d.Attributes(AttributeType.attr_vertex).ToList() .ValidateArity(3) .ValidateDataType(DataType.dt_float32, DataType.dt_float64) .ValidateAssociation(Association.assoc_vertex) .ValidateExactlyOne(); }
public static IArray <int> CornerVertexIndices(this IG3D g3d) => g3d.IndexAttribute == null ? g3d.VertexCount().Range() : g3d.IndexAttribute.ToInts();