Using LINQ

And also change types from using LINQ
This commit is contained in:
Adam Moy 2025-02-12 12:45:15 -06:00
parent 369efdb5dc
commit 307b987eee

View file

@ -82,16 +82,16 @@ public class MeshExporter
if (skeleton != null) if (skeleton != null)
_boneIndexMap = BuildBoneIndexMap(skeleton.Value); _boneIndexMap = BuildBoneIndexMap(skeleton.Value);
var usages = new Dictionary<MdlFile.VertexUsage, IDictionary<byte, MdlFile.VertexType>>();
foreach (var element in _mdl.VertexDeclarations[_meshIndex].VertexElements) var usages = _mdl.VertexDeclarations[_meshIndex].VertexElements
{ .GroupBy(ele => (MdlFile.VertexUsage)ele.Usage, ele => ele)
if (!usages.ContainsKey((MdlFile.VertexUsage)element.Usage)) .ToImmutableDictionary(
{ g => g.Key,
usages.Add((MdlFile.VertexUsage)element.Usage, new Dictionary<byte, MdlFile.VertexType>()); g => g.OrderBy(ele => ele.UsageIndex) // OrderBy UsageIndex is probably unnecessary as they're probably already be in order
} .Select(ele => (MdlFile.VertexType)ele.Type)
usages[(MdlFile.VertexUsage)element.Usage][element.UsageIndex] = (MdlFile.VertexType)element.Type; .ToList()
} );
_geometryType = GetGeometryType(usages); _geometryType = GetGeometryType(usages);
_materialType = GetMaterialType(usages); _materialType = GetMaterialType(usages);
_skinningType = GetSkinningType(usages); _skinningType = GetSkinningType(usages);
@ -287,25 +287,22 @@ public class MeshExporter
var sortedElements = _mdl.VertexDeclarations[_meshIndex].VertexElements var sortedElements = _mdl.VertexDeclarations[_meshIndex].VertexElements
.OrderBy(element => element.Offset) .OrderBy(element => element.Offset)
.Select(element => ((MdlFile.VertexUsage)element.Usage, element))
.ToList(); .ToList();
var vertices = new List<IVertexBuilder>(); var vertices = new List<IVertexBuilder>();
var attributes = new Dictionary<MdlFile.VertexUsage, Dictionary<byte, object>>(); var attributes = new Dictionary<MdlFile.VertexUsage, List<object>>();
for (var vertexIndex = 0; vertexIndex < XivMesh.VertexCount; vertexIndex++) for (var vertexIndex = 0; vertexIndex < XivMesh.VertexCount; vertexIndex++)
{ {
attributes.Clear(); attributes.Clear();
foreach (var (usage, element) in sortedElements) attributes = sortedElements
{ .GroupBy(element => element.Usage)
if (!attributes.TryGetValue(usage, out var value)) .ToDictionary(
{ x => (MdlFile.VertexUsage)x.Key,
value = new Dictionary<byte, object>(); x => x.OrderBy(ele => ele.UsageIndex) // Once again, OrderBy UsageIndex is probably unnecessary
attributes[usage] = value; .Select(ele => ReadVertexAttribute((MdlFile.VertexType)ele.Type, streams[ele.Stream]))
} .ToList()
);
value[element.UsageIndex] = ReadVertexAttribute((MdlFile.VertexType)element.Type, streams[element.Stream]);
}
var vertexGeometry = BuildVertexGeometry(attributes); var vertexGeometry = BuildVertexGeometry(attributes);
var vertexMaterial = BuildVertexMaterial(attributes); var vertexMaterial = BuildVertexMaterial(attributes);
@ -336,7 +333,7 @@ public class MeshExporter
} }
/// <summary> Get the vertex geometry type for this mesh's vertex usages. </summary> /// <summary> Get the vertex geometry type for this mesh's vertex usages. </summary>
private Type GetGeometryType(IReadOnlyDictionary<MdlFile.VertexUsage, IDictionary<byte, MdlFile.VertexType>> usages) private Type GetGeometryType(IReadOnlyDictionary<MdlFile.VertexUsage, List<MdlFile.VertexType>> usages)
{ {
if (!usages.ContainsKey(MdlFile.VertexUsage.Position)) if (!usages.ContainsKey(MdlFile.VertexUsage.Position))
throw _notifier.Exception("Mesh does not contain position vertex elements."); throw _notifier.Exception("Mesh does not contain position vertex elements.");
@ -351,28 +348,28 @@ public class MeshExporter
} }
/// <summary> Build a geometry vertex from a vertex's attributes. </summary> /// <summary> Build a geometry vertex from a vertex's attributes. </summary>
private IVertexGeometry BuildVertexGeometry(IReadOnlyDictionary<MdlFile.VertexUsage, Dictionary<byte, object>> attributes) private IVertexGeometry BuildVertexGeometry(IReadOnlyDictionary<MdlFile.VertexUsage, List<object>> attributes)
{ {
if (_geometryType == typeof(VertexPosition)) if (_geometryType == typeof(VertexPosition))
return new VertexPosition( return new VertexPosition(
ToVector3(attributes[MdlFile.VertexUsage.Position].First().Value) ToVector3(attributes[MdlFile.VertexUsage.Position].First())
); );
if (_geometryType == typeof(VertexPositionNormal)) if (_geometryType == typeof(VertexPositionNormal))
return new VertexPositionNormal( return new VertexPositionNormal(
ToVector3(attributes[MdlFile.VertexUsage.Position].First().Value), ToVector3(attributes[MdlFile.VertexUsage.Position].First()),
ToVector3(attributes[MdlFile.VertexUsage.Normal].First().Value) ToVector3(attributes[MdlFile.VertexUsage.Normal].First())
); );
if (_geometryType == typeof(VertexPositionNormalTangent)) if (_geometryType == typeof(VertexPositionNormalTangent))
{ {
// (Bi)tangents are universally stored as ByteFloat4, which uses 0..1 to represent the full -1..1 range. // (Bi)tangents are universally stored as ByteFloat4, which uses 0..1 to represent the full -1..1 range.
// TODO: While this assumption is safe, it would be sensible to actually check. // TODO: While this assumption is safe, it would be sensible to actually check.
var bitangent = ToVector4(attributes[MdlFile.VertexUsage.Tangent1].First().Value) * 2 - Vector4.One; var bitangent = ToVector4(attributes[MdlFile.VertexUsage.Tangent1].First()) * 2 - Vector4.One;
return new VertexPositionNormalTangent( return new VertexPositionNormalTangent(
ToVector3(attributes[MdlFile.VertexUsage.Position].First().Value), ToVector3(attributes[MdlFile.VertexUsage.Position].First()),
ToVector3(attributes[MdlFile.VertexUsage.Normal].First().Value), ToVector3(attributes[MdlFile.VertexUsage.Normal].First()),
bitangent bitangent
); );
} }
@ -381,12 +378,12 @@ public class MeshExporter
} }
/// <summary> Get the vertex material type for this mesh's vertex usages. </summary> /// <summary> Get the vertex material type for this mesh's vertex usages. </summary>
private Type GetMaterialType(IReadOnlyDictionary<MdlFile.VertexUsage, IDictionary<byte, MdlFile.VertexType>> usages) private Type GetMaterialType(IReadOnlyDictionary<MdlFile.VertexUsage, List<MdlFile.VertexType>> usages)
{ {
var uvCount = 0; var uvCount = 0;
if (usages.TryGetValue(MdlFile.VertexUsage.UV, out var dict)) if (usages.TryGetValue(MdlFile.VertexUsage.UV, out var list))
{ {
foreach (var type in dict.Values) foreach (var type in list)
{ {
uvCount += type switch uvCount += type switch
{ {
@ -420,28 +417,28 @@ public class MeshExporter
} }
/// <summary> Build a material vertex from a vertex's attributes. </summary> /// <summary> Build a material vertex from a vertex's attributes. </summary>
private IVertexMaterial BuildVertexMaterial(IReadOnlyDictionary<MdlFile.VertexUsage, Dictionary<byte, object>> attributes) private IVertexMaterial BuildVertexMaterial(IReadOnlyDictionary<MdlFile.VertexUsage, List<object>> attributes)
{ {
if (_materialType == typeof(VertexEmpty)) if (_materialType == typeof(VertexEmpty))
return new VertexEmpty(); return new VertexEmpty();
if (_materialType == typeof(VertexColorFfxiv)) if (_materialType == typeof(VertexColorFfxiv))
return new VertexColorFfxiv(ToVector4(attributes[MdlFile.VertexUsage.Color].First().Value)); return new VertexColorFfxiv(ToVector4(attributes[MdlFile.VertexUsage.Color].First()));
if (_materialType == typeof(VertexTexture1)) if (_materialType == typeof(VertexTexture1))
return new VertexTexture1(ToVector2(attributes[MdlFile.VertexUsage.UV].First().Value)); return new VertexTexture1(ToVector2(attributes[MdlFile.VertexUsage.UV].First()));
if (_materialType == typeof(VertexTexture1ColorFfxiv)) if (_materialType == typeof(VertexTexture1ColorFfxiv))
return new VertexTexture1ColorFfxiv( return new VertexTexture1ColorFfxiv(
ToVector2(attributes[MdlFile.VertexUsage.UV].First().Value), ToVector2(attributes[MdlFile.VertexUsage.UV].First()),
ToVector4(attributes[MdlFile.VertexUsage.Color].First().Value) ToVector4(attributes[MdlFile.VertexUsage.Color].First())
); );
// XIV packs two UVs into a single vec4 attribute. // XIV packs two UVs into a single vec4 attribute.
if (_materialType == typeof(VertexTexture2)) if (_materialType == typeof(VertexTexture2))
{ {
var uv = ToVector4(attributes[MdlFile.VertexUsage.UV].First().Value); var uv = ToVector4(attributes[MdlFile.VertexUsage.UV].First());
return new VertexTexture2( return new VertexTexture2(
new Vector2(uv.X, uv.Y), new Vector2(uv.X, uv.Y),
new Vector2(uv.Z, uv.W) new Vector2(uv.Z, uv.W)
@ -450,11 +447,11 @@ public class MeshExporter
if (_materialType == typeof(VertexTexture2ColorFfxiv)) if (_materialType == typeof(VertexTexture2ColorFfxiv))
{ {
var uv = ToVector4(attributes[MdlFile.VertexUsage.UV].First().Value); var uv = ToVector4(attributes[MdlFile.VertexUsage.UV].First());
return new VertexTexture2ColorFfxiv( return new VertexTexture2ColorFfxiv(
new Vector2(uv.X, uv.Y), new Vector2(uv.X, uv.Y),
new Vector2(uv.Z, uv.W), new Vector2(uv.Z, uv.W),
ToVector4(attributes[MdlFile.VertexUsage.Color].First().Value) ToVector4(attributes[MdlFile.VertexUsage.Color].First())
); );
} }
if (_materialType == typeof(VertexTexture3)) if (_materialType == typeof(VertexTexture3))
@ -470,7 +467,7 @@ public class MeshExporter
new Vector2(uv0.X, uv0.Y), new Vector2(uv0.X, uv0.Y),
new Vector2(uv0.Z, uv0.W), new Vector2(uv0.Z, uv0.W),
new Vector2(uv1.X, uv1.Y), new Vector2(uv1.X, uv1.Y),
ToVector4(attributes[MdlFile.VertexUsage.Color].First().Value) ToVector4(attributes[MdlFile.VertexUsage.Color].First())
); );
} }
@ -478,11 +475,11 @@ public class MeshExporter
} }
/// <summary> Get the vertex skinning type for this mesh's vertex usages. </summary> /// <summary> Get the vertex skinning type for this mesh's vertex usages. </summary>
private static Type GetSkinningType(IReadOnlyDictionary<MdlFile.VertexUsage, IDictionary<byte, MdlFile.VertexType>> usages) private static Type GetSkinningType(IReadOnlyDictionary<MdlFile.VertexUsage, List<MdlFile.VertexType>> usages)
{ {
if (usages.ContainsKey(MdlFile.VertexUsage.BlendWeights) && usages.ContainsKey(MdlFile.VertexUsage.BlendIndices)) if (usages.ContainsKey(MdlFile.VertexUsage.BlendWeights) && usages.ContainsKey(MdlFile.VertexUsage.BlendIndices))
{ {
if (usages[MdlFile.VertexUsage.BlendWeights].First().Value == MdlFile.VertexType.UShort4) if (usages[MdlFile.VertexUsage.BlendWeights].First() == MdlFile.VertexType.UShort4)
{ {
return typeof(VertexJoints8); return typeof(VertexJoints8);
} }
@ -496,7 +493,7 @@ public class MeshExporter
} }
/// <summary> Build a skinning vertex from a vertex's attributes. </summary> /// <summary> Build a skinning vertex from a vertex's attributes. </summary>
private IVertexSkinning BuildVertexSkinning(IReadOnlyDictionary<MdlFile.VertexUsage, Dictionary<byte, object>> attributes) private IVertexSkinning BuildVertexSkinning(IReadOnlyDictionary<MdlFile.VertexUsage, List<object>> attributes)
{ {
if (_skinningType == typeof(VertexEmpty)) if (_skinningType == typeof(VertexEmpty))
return new VertexEmpty(); return new VertexEmpty();
@ -506,8 +503,8 @@ public class MeshExporter
if (_boneIndexMap == null) if (_boneIndexMap == null)
throw _notifier.Exception("Tried to build skinned vertex but no bone mappings are available."); throw _notifier.Exception("Tried to build skinned vertex but no bone mappings are available.");
var indiciesData = attributes[MdlFile.VertexUsage.BlendIndices].First().Value; var indiciesData = attributes[MdlFile.VertexUsage.BlendIndices].First();
var weightsData = attributes[MdlFile.VertexUsage.BlendWeights].First().Value; var weightsData = attributes[MdlFile.VertexUsage.BlendWeights].First();
var indices = ToByteArray(indiciesData); var indices = ToByteArray(indiciesData);
var weights = ToFloatArray(weightsData); var weights = ToFloatArray(weightsData);