This commit is contained in:
Ottermandias 2024-01-23 23:23:03 +01:00
parent b2bd31a166
commit a159ef28c3
5 changed files with 47 additions and 39 deletions

View file

@ -2,11 +2,11 @@ using Lumina.Data.Parsing;
namespace Penumbra.Import.Models.Import;
/// <summary> Mutable representation of the bounding box surrouding a collection of vertices. </summary>
/// <summary> Mutable representation of the bounding box surrounding a collection of vertices. </summary>
public class BoundingBox
{
private Vector3 _minimum = new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
private Vector3 _maximum = new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
private Vector3 _minimum = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
private Vector3 _maximum = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
/// <summary> Use the specified position to update this bounding box, expanding it if necessary. </summary>
public void Merge(Vector3 position)
@ -25,7 +25,7 @@ public class BoundingBox
/// <summary> Convert this bounding box to the struct format used in .mdl data structures. </summary>
public MdlStructs.BoundingBoxStruct ToStruct()
=> new MdlStructs.BoundingBoxStruct
=> new()
{
Min = [_minimum.X, _minimum.Y, _minimum.Z, 1],
Max = [_maximum.X, _maximum.Y, _maximum.Z, 1],

View file

@ -53,7 +53,7 @@ public class MeshImporter(IEnumerable<Node> nodes, IoNotifier notifier)
private List<string>? _bones;
private readonly BoundingBox _boundingBox = new BoundingBox();
private readonly BoundingBox _boundingBox = new();
private readonly List<string> _metaAttributes = [];
@ -124,7 +124,8 @@ public class MeshImporter(IEnumerable<Node> nodes, IoNotifier notifier)
_material ??= subMesh.Material;
if (subMesh.Material != null && _material != subMesh.Material)
notifier.Warning($"Meshes may only reference one material. Sub-mesh {subMeshName} material \"{subMesh.Material}\" has been ignored.");
notifier.Warning(
$"Meshes may only reference one material. Sub-mesh {subMeshName} material \"{subMesh.Material}\" has been ignored.");
// Check that vertex declarations match - we need to combine the buffers, so a mismatch would take a whole load of resolution.
if (_vertexDeclaration == null)

View file

@ -35,21 +35,21 @@ public class PrimitiveImporter
private readonly IDictionary<ushort, ushort>? _nodeBoneMap;
private ushort[]? _indices;
private List<VertexAttribute>? _vertexAttributes;
private ushort _vertexCount;
private byte[] _strides = [0, 0, 0];
private readonly List<byte>[] _streams = [[], [], []];
private BoundingBox _boundingBox = new BoundingBox();
private readonly BoundingBox _boundingBox = new();
private List<List<MdlStructs.ShapeValueStruct>>? _shapeValues;
private PrimitiveImporter(MeshPrimitive primitive, IDictionary<ushort, ushort>? nodeBoneMap, IoNotifier notifier)
{
_notifier = notifier;
_primitive = primitive;
_notifier = notifier;
_primitive = primitive;
_nodeBoneMap = nodeBoneMap;
}
@ -154,9 +154,10 @@ public class PrimitiveImporter
_streams[attribute.Stream].AddRange(attribute.Build(vertexIndex));
// Record which morph targets have values for this vertex, if any.
var index = vertexIndex;
var changedMorphs = morphModifiedVertices
.WithIndex()
.Where(pair => _vertexAttributes.Any(attribute => attribute.HasMorph(pair.Index, vertexIndex)))
.Where(pair => _vertexAttributes.Any(attribute => attribute.HasMorph(pair.Index, index)))
.Select(pair => pair.Value);
foreach (var modifiedVertices in changedMorphs)
modifiedVertices.Add(vertexIndex);
@ -200,7 +201,7 @@ public class PrimitiveImporter
_shapeValues = morphShapeValues;
}
private void BuildBoundingBox()
{
var positions = _primitive.VertexAccessors["POSITION"].AsVector3Array();

View file

@ -46,12 +46,12 @@ public class SubMeshImporter
private byte[]? _strides;
private readonly List<byte>[] _streams = [[], [], []];
private List<ushort> _indices = [];
private readonly List<ushort> _indices = [];
private BoundingBox _boundingBox = new BoundingBox();
private readonly BoundingBox _boundingBox = new();
private readonly List<string>? _morphNames;
private Dictionary<string, List<MdlStructs.ShapeValueStruct>> _shapeValues = [];
private readonly Dictionary<string, List<MdlStructs.ShapeValueStruct>> _shapeValues = [];
private SubMeshImporter(Node node, IDictionary<ushort, ushort>? nodeBoneMap, IoNotifier notifier)
{
@ -86,7 +86,7 @@ public class SubMeshImporter
var attributeMask = metaAttributes.Length switch
{
< 32 => (1u << metaAttributes.Length) - 1,
32 => uint.MaxValue,
32 => uint.MaxValue,
> 32 => throw _notifier.Exception("Models may utilise a maximum of 32 attributes."),
};
@ -102,22 +102,22 @@ public class SubMeshImporter
BoneStartIndex = 0,
BoneCount = 0,
},
Material = _material,
Material = _material,
VertexDeclaration = _vertexDeclaration.Value,
VertexCount = _vertexCount,
Strides = _strides,
Streams = _streams,
Indices = _indices,
BoundingBox = _boundingBox,
MetaAttributes = metaAttributes,
ShapeValues = _shapeValues,
VertexCount = _vertexCount,
Strides = _strides,
Streams = _streams,
Indices = _indices,
BoundingBox = _boundingBox,
MetaAttributes = metaAttributes,
ShapeValues = _shapeValues,
};
}
private void BuildPrimitive(MeshPrimitive meshPrimitive, int index)
{
var vertexOffset = _vertexCount;
var indexOffset = _indices.Count;
var indexOffset = _indices.Count;
var primitive = PrimitiveImporter.Import(meshPrimitive, _nodeBoneMap, _notifier.WithContext($"Primitive {index}"));
@ -141,7 +141,7 @@ public class SubMeshImporter
stream.AddRange(primitiveStream);
// Indices
_indices.AddRange(primitive.Indices.Select(index => (ushort)(index + vertexOffset)));
_indices.AddRange(primitive.Indices.Select(i => (ushort)(i + vertexOffset)));
// Shape values
foreach (var (primitiveShapeValues, morphIndex) in primitive.ShapeValues.WithIndex())
@ -181,8 +181,9 @@ public class SubMeshImporter
// We consider any "extras" key with a boolean value set to `true` to be an attribute.
return nodeExtras?
.Where(pair => pair.Value.ValueKind == JsonValueKind.True)
.Select(pair => pair.Key)
.ToArray() ?? [];
.Where(pair => pair.Value.ValueKind == JsonValueKind.True)
.Select(pair => pair.Key)
.ToArray()
?? [];
}
}

View file

@ -4,11 +4,11 @@ namespace Penumbra.Import.Models.Import;
public static class Utility
{
/// <summary> Merge attributes into an existing attribute array, providing an updated submesh mask. </summary>
/// <param name="oldMask"> Old submesh attribute mask. </param>
/// <summary> Merge attributes into an existing attribute array, providing an updated sub mesh mask. </summary>
/// <param name="oldMask"> Old sub mesh attribute mask. </param>
/// <param name="oldAttributes"> Old attribute array that should be merged. </param>
/// <param name="newAttributes"> New attribute array. Will be mutated. </param>
/// <returns> New submesh attribute mask, updated to match the merged attribute array. </returns>
/// <returns> New sub mesh attribute mask, updated to match the merged attribute array. </returns>
public static uint GetMergedAttributeMask(uint oldMask, IList<string> oldAttributes, List<string> newAttributes)
{
var metaAttributes = Enumerable.Range(0, 32)
@ -28,6 +28,7 @@ public static class Utility
newAttributes.Add(metaAttribute);
attributeIndex = newAttributes.Count - 1;
}
newMask |= 1u << attributeIndex;
}
@ -35,18 +36,22 @@ public static class Utility
}
/// <summary> Ensures that the two vertex declarations provided are equal, throwing if not. </summary>
public static void EnsureVertexDeclarationMatch(MdlStructs.VertexDeclarationStruct current, MdlStructs.VertexDeclarationStruct @new, IoNotifier notifier)
public static void EnsureVertexDeclarationMatch(MdlStructs.VertexDeclarationStruct current, MdlStructs.VertexDeclarationStruct @new,
IoNotifier notifier)
{
if (VertexDeclarationMismatch(current, @new))
throw notifier.Exception(
$@"All sub-meshes of a mesh must have equivalent vertex declarations.
Current: {FormatVertexDeclaration(current)}
New: {FormatVertexDeclaration(@new)}"
$"""
All sub-meshes of a mesh must have equivalent vertex declarations.
Current: {FormatVertexDeclaration(current)}
New: {FormatVertexDeclaration(@new)}
"""
);
}
private static string FormatVertexDeclaration(MdlStructs.VertexDeclarationStruct vertexDeclaration)
=> string.Join(", ", vertexDeclaration.VertexElements.Select(element => $"{element.Usage} ({element.Type}@{element.Stream}:{element.Offset})"));
=> string.Join(", ",
vertexDeclaration.VertexElements.Select(element => $"{element.Usage} ({element.Type}@{element.Stream}:{element.Offset})"));
private static bool VertexDeclarationMismatch(MdlStructs.VertexDeclarationStruct a, MdlStructs.VertexDeclarationStruct b)
{