Skip to content

Commit 668a824

Browse files
committed
SimpleHeels stuff
1 parent d94fdac commit 668a824

File tree

1 file changed

+98
-36
lines changed

1 file changed

+98
-36
lines changed

xivModdingFramework/Models/Helpers/ModelModifiers.cs

Lines changed: 98 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ public class ModelImportOptions : ICloneable
5151

5252
public bool ClearEmptyMeshData { get; set; }
5353

54+
public bool AutoAssignHeels { get; set; }
55+
5456
/// <summary>
5557
/// Logging output function.
5658
/// </summary>
@@ -83,6 +85,7 @@ public ModelImportOptions()
8385
SourceApplication = "Unknown";
8486
ReferenceItem = null;
8587
ClearEmptyMeshData = false;
88+
AutoAssignHeels = true;
8689
}
8790

8891

@@ -177,6 +180,11 @@ public async Task Apply(TTModel ttModel, XivMdl currentMdl = null, XivMdl origin
177180
}
178181
}
179182

183+
if (AutoAssignHeels)
184+
{
185+
ModelModifiers.AssignHeelAttribute(ttModel, LoggingFunction);
186+
}
187+
180188
// Ensure shape data is updated with our various changes.
181189
ttModel.UpdateShapeData();
182190
}
@@ -290,14 +298,14 @@ public static void AutoScaleModel(TTModel ttModel, TTModel originalModel, double
290298
0.00254D,
291299
};
292300

293-
foreach(var conversion in possibleConversions)
301+
foreach (var conversion in possibleConversions)
294302
{
295303
var nSize = NewModelSize * conversion;
296304
var diff = (OldModelSize - nSize) / OldModelSize;
297305

298-
if(Math.Abs(diff) < tolerance)
306+
if (Math.Abs(diff) < tolerance)
299307
{
300-
if(conversion != 1.0D)
308+
if (conversion != 1.0D)
301309
{
302310
loggingFunction(true, "Correcting Scaling Error: Rescaling model by " + conversion);
303311
ScaleModel(ttModel, conversion, loggingFunction);
@@ -325,7 +333,7 @@ public static void ScaleModel(TTModel ttModel, double scale, Action<bool, string
325333

326334
foreach (var m in ttModel.MeshGroups)
327335
{
328-
foreach(var p in m.Parts)
336+
foreach (var p in m.Parts)
329337
{
330338
foreach (var v in p.Vertices)
331339
{
@@ -349,7 +357,7 @@ public static void MergeMeshTypes(TTModel ttModel, XivMdl rawMdl, Action<bool, s
349357
var meshIdx = 0;
350358
foreach (var baseMesh in rawMdl.LoDList[0].MeshDataList)
351359
{
352-
if(meshIdx >= ttModel.MeshGroups.Count)
360+
if (meshIdx >= ttModel.MeshGroups.Count)
353361
{
354362
continue;
355363
}
@@ -374,7 +382,7 @@ public static void MergeGeometryData(TTModel ttModel, XivMdl rawMdl, Action<bool
374382

375383
var meshIdx = 0;
376384
var totalPartIdx = 0;
377-
foreach(var baseMesh in rawMdl.LoDList[0].MeshDataList)
385+
foreach (var baseMesh in rawMdl.LoDList[0].MeshDataList)
378386
{
379387
var ttMesh = new TTMeshGroup();
380388
ttModel.MeshGroups.Add(ttMesh);
@@ -409,7 +417,7 @@ public static void MergeGeometryData(TTModel ttModel, XivMdl rawMdl, Action<bool
409417
totalParts = 1;
410418
}
411419

412-
for(var pi = 0; pi < totalParts; pi++)
420+
for (var pi = 0; pi < totalParts; pi++)
413421
{
414422

415423
var ttPart = new TTMeshPart();
@@ -426,7 +434,7 @@ public static void MergeGeometryData(TTModel ttModel, XivMdl rawMdl, Action<bool
426434
// Get the Vertices unique to this part.
427435
var uniqueVertexIdSet = new SortedSet<int>(indices); // Maximum possible amount is # of indices, though likely it is less.
428436

429-
foreach(var ind in indices)
437+
foreach (var ind in indices)
430438
{
431439
uniqueVertexIdSet.Add(ind);
432440
}
@@ -439,7 +447,7 @@ public static void MergeGeometryData(TTModel ttModel, XivMdl rawMdl, Action<bool
439447

440448
// Now we need to loop through, copy over the vertex data, keeping track of the new vertex IDs.
441449
ttPart.Vertices = new List<TTVertex>(uniqueVertexIds.Count);
442-
for(var i = 0; i < uniqueVertexIds.Count; i++)
450+
for (var i = 0; i < uniqueVertexIds.Count; i++)
443451
{
444452
var oldVertexId = uniqueVertexIds[i];
445453
var ttVert = new TTVertex();
@@ -499,7 +507,7 @@ public static void MergeGeometryData(TTModel ttModel, XivMdl rawMdl, Action<bool
499507
ttVert.UV2.X = 0;
500508
}
501509

502-
if(float.IsNaN(ttVert.UV2.Y))
510+
if (float.IsNaN(ttVert.UV2.Y))
503511
{
504512
ttVert.UV2.Y = 0;
505513
}
@@ -523,11 +531,11 @@ public static void MergeGeometryData(TTModel ttModel, XivMdl rawMdl, Action<bool
523531

524532
var vertexBoneArrayLength = baseMesh.VertexBoneArraySize;
525533
// Now for the fun part, establishing bones.
526-
for(var bIdx = 0; bIdx < vertexBoneArrayLength; bIdx++)
534+
for (var bIdx = 0; bIdx < vertexBoneArrayLength; bIdx++)
527535
{
528536
// Vertex doesn't have weights.
529537
if (baseMesh.VertexData.BoneWeights.Count <= oldVertexId) break;
530-
538+
531539
// No more weights for this vertex.
532540
if (baseMesh.VertexData.BoneIndices[oldVertexId].Length <= bIdx) break;
533541

@@ -541,8 +549,8 @@ public static void MergeGeometryData(TTModel ttModel, XivMdl rawMdl, Action<bool
541549
// These seem to actually be irrelevant, and the bone ID is just routed directly to the mesh level identifier.
542550
// var partBoneSet = rawMdl.PartBoneSets.BoneIndices.GetRange(basePart.BoneStartOffset, basePart.BoneCount);
543551

544-
ttVert.BoneIds[bIdx] = (byte) boneId;
545-
ttVert.Weights[bIdx] = (byte) Math.Round(weight * 255);
552+
ttVert.BoneIds[bIdx] = (byte)boneId;
553+
ttVert.Weights[bIdx] = (byte)Math.Round(weight * 255);
546554
}
547555

548556
ttPart.Vertices.Add(ttVert);
@@ -732,7 +740,7 @@ public static void MergeShapeData(TTModel ttModel, XivMdl ogMdl, Action<bool, st
732740
badPart = true;
733741
break;
734742
}
735-
743+
736744
vertexReplacements.Add(ogGroup.VertexData.Indices[d.BaseIndex], vId);
737745

738746
var vert = new TTVertex();
@@ -780,18 +788,18 @@ public static void MergeShapeData(TTModel ttModel, XivMdl ogMdl, Action<bool, st
780788
vertices.Add(vId, vert);
781789
}
782790

783-
if(badPart)
791+
if (badPart)
784792
{
785793
continue;
786794
}
787795

788796
// Now we need to go through and create the shape part objects for each part.
789797
Dictionary<int, TTShapePart> shapeParts = new Dictionary<int, TTShapePart>();
790-
foreach(var kv in vertexReplacements)
798+
foreach (var kv in vertexReplacements)
791799
{
792800
// For every vertex which was replaced, we need to identify what part owned it.
793801
var info = ttMesh.GetPartRelevantVertexInformation(kv.Key);
794-
if(!shapeParts.ContainsKey(info.PartId))
802+
if (!shapeParts.ContainsKey(info.PartId))
795803
{
796804
var tempShp = new TTShapePart();
797805
tempShp.Name = shp.ShapeName;
@@ -807,10 +815,10 @@ public static void MergeShapeData(TTModel ttModel, XivMdl ogMdl, Action<bool, st
807815
}
808816

809817
// Now just add the shapes to the associated TTParts
810-
foreach(var kv in shapeParts)
818+
foreach (var kv in shapeParts)
811819
{
812820
if (kv.Key == -1) continue;
813-
if(ttMesh.Parts[kv.Key].ShapeParts.Count == 0)
821+
if (ttMesh.Parts[kv.Key].ShapeParts.Count == 0)
814822
{
815823
// Pretty janky, but a simple enough way to guarantee we can always
816824
// restore back to the original shape.
@@ -860,9 +868,9 @@ public static void ForceUVQuadrant(TTModel model, Action<bool, string> loggingFu
860868
}
861869

862870
loggingFunction(false, "Forcing UV1 to [1,-1]...");
863-
foreach(var m in model.MeshGroups)
871+
foreach (var m in model.MeshGroups)
864872
{
865-
foreach(var p in m.Parts)
873+
foreach (var p in m.Parts)
866874
{
867875
bool anyNegativeX = p.Vertices.Any(x => x.UV1.X < 0);
868876
bool anyPositiveY = p.Vertices.Any(x => x.UV1.Y > 0);
@@ -883,7 +891,7 @@ public static void ForceUVQuadrant(TTModel model, Action<bool, string> loggingFu
883891
// The extra [anyPositive/negative] values check is to avoid potentially
884892
// shifting values at exactly 0 if 0 is effectively the "top" of the
885893
// used UV space.
886-
894+
887895
// The goal here is to allow the user to have used any exact quadrant in the [-1 - 1, -1 - 1] range
888896
// and maintain the UV correctly, even if they used exactly [1,1] as a coordinate, for example.
889897

@@ -1076,7 +1084,7 @@ private static void UpdateShapeParts(TTMeshPart p)
10761084
{
10771085
var shpVertex = shpKv.Value.Vertices[vKv.Value];
10781086
var pVertex = p.Vertices[vKv.Key];
1079-
var newVert = (TTVertex) pVertex.Clone();
1087+
var newVert = (TTVertex)pVertex.Clone();
10801088
newVert.Position = shpVertex.Position;
10811089
shpKv.Value.Vertices[vKv.Value] = newVert;
10821090
}
@@ -1135,7 +1143,7 @@ public static async Task RaceConvertRecursive(TTModel model, XivRace targetRace,
11351143
await CalculateTangents(model, loggingFunction, true);
11361144
}
11371145
private static async Task INTERNAL_RaceConvertRecursive(TTModel model, XivRace targetRace, XivRace originalRace, Action<bool, string> loggingFunction = null, ModTransaction tx = null)
1138-
{
1146+
{
11391147
try
11401148
{
11411149
if (originalRace.IsDirectParentOf(targetRace))
@@ -1250,12 +1258,12 @@ public static async Task ApplyRacialDeform(TTModel model, XivRace targetRace, bo
12501258
var parent = dict.FirstOrDefault(x => x.Value.BoneNumber == dict[bone].BoneParent).Value;
12511259

12521260
// Walk up the tree until we find a parent with a deform.
1253-
while(parent != null && !def.Deformations.ContainsKey(parent.BoneName))
1261+
while (parent != null && !def.Deformations.ContainsKey(parent.BoneName))
12541262
{
12551263
parent = dict.FirstOrDefault(x => x.Value.BoneNumber == parent.BoneParent).Value;
12561264
}
12571265

1258-
if(parent != null)
1266+
if (parent != null)
12591267
{
12601268
// Found a parent? use that bone's deforms.
12611269
def.Deformations[bone] = def.Deformations[parent.BoneName];
@@ -1426,7 +1434,7 @@ public static async Task ApplyRacialDeform(TTModel model, XivRace targetRace, bo
14261434
}
14271435
}
14281436
}
1429-
catch(Exception ex)
1437+
catch (Exception ex)
14301438
{
14311439
throw;
14321440
}
@@ -1444,9 +1452,9 @@ public static async Task ApplyRacialDeform(TTModel model, XivRace targetRace, bo
14441452
private static Vector3 MatrixTransform(Vector3 vector, Matrix transform)
14451453
{
14461454
var result = new Vector3(
1447-
(vector.X * transform[0]) + (vector.Y * transform[1]) + (vector.Z * transform[2]) + (1.0f * transform[3]),
1448-
(vector.X * transform[4]) + (vector.Y * transform[5]) + (vector.Z * transform[6]) + (1.0f * transform[7]),
1449-
(vector.X * transform[8]) + (vector.Y * transform[9]) + (vector.Z * transform[10]) + (1.0f * transform[11]));
1455+
(vector.X * transform[0]) + (vector.Y * transform[1]) + (vector.Z * transform[2]) + (1.0f * transform[3]),
1456+
(vector.X * transform[4]) + (vector.Y * transform[5]) + (vector.Z * transform[6]) + (1.0f * transform[7]),
1457+
(vector.X * transform[8]) + (vector.Y * transform[9]) + (vector.Z * transform[10]) + (1.0f * transform[11]));
14501458

14511459
return result;
14521460
}
@@ -1494,7 +1502,7 @@ public static bool CleanWeight(TTVertex v, int maxWeights = 4, Action<bool, stri
14941502

14951503
int boneSum = 0;
14961504
var sum = v.Weights.Select(x => (int)x).Aggregate((sum, x) => sum + x);
1497-
if(sum == 255)
1505+
if (sum == 255)
14981506
{
14991507
return false;
15001508
}
@@ -1589,7 +1597,7 @@ public static void CleanWeights(TTModel model, Action<bool, string> loggingFunct
15891597
foreach (var v in p.Vertices)
15901598
{
15911599
bool majorCorrection = false;
1592-
if(usage.NeedsEightWeights)
1600+
if (usage.NeedsEightWeights)
15931601
{
15941602
majorCorrection = CleanWeight(v, 8, loggingFunction);
15951603
} else
@@ -1673,13 +1681,13 @@ internal static async Task ConvertFlowData(TTModel model, Action<bool, string> l
16731681

16741682

16751683
var tasks = new List<Task>();
1676-
foreach(var m in model.MeshGroups)
1684+
foreach (var m in model.MeshGroups)
16771685
{
1678-
foreach(var p in m.Parts)
1686+
foreach (var p in m.Parts)
16791687
{
16801688
tasks.Add(Task.Run(() =>
16811689
{
1682-
foreach(var v in p.Vertices)
1690+
foreach (var v in p.Vertices)
16831691
{
16841692
var f = new float[3];
16851693

@@ -1739,6 +1747,60 @@ internal static void MakeExportReady(TTModel model, bool shiftUv = true, Action<
17391747
model.UVState = TTModel.UVAddressingSpace.Standard;
17401748
}
17411749

1750+
public static string AssignHeelAttribute(TTModel model, Action<bool, string> loggingFunction = null)
1751+
{
1752+
if (model == null || !model.HasPath)
1753+
{
1754+
return "";
1755+
}
1756+
loggingFunction ??= NoOp;
1757+
1758+
if (!model.Source.EndsWith("_top.mdl")
1759+
&& !model.Source.EndsWith("_dwn.mdl")
1760+
&& !model.Source.EndsWith("_sho.mdl")) {
1761+
return "";
1762+
}
1763+
const string _Prefix = "heels_offset=";
1764+
1765+
loggingFunction?.Invoke(false, "Assigning Heel Attributes...");
1766+
1767+
var max = float.MaxValue;
1768+
TTMeshPart first = null;
1769+
foreach(var m in model.MeshGroups)
1770+
{
1771+
foreach(var p in m.Parts)
1772+
{
1773+
foreach(var v in p.Vertices)
1774+
{
1775+
if(v.Position.Y < max)
1776+
{
1777+
max = v.Position.Y;
1778+
}
1779+
}
1780+
1781+
first ??= p;
1782+
}
1783+
}
1784+
1785+
if (max < 0)
1786+
{
1787+
foreach (var m in model.MeshGroups)
1788+
{
1789+
foreach (var p in m.Parts)
1790+
{
1791+
p.Attributes.RemoveWhere(x => x.StartsWith(_Prefix));
1792+
}
1793+
}
1794+
1795+
// Offset is inverted, since it's bringing the character to 0.
1796+
max *= -1;
1797+
var atr = _Prefix + max.ToString("0.0000");
1798+
first.Attributes.Add(atr);
1799+
return atr;
1800+
}
1801+
return "";
1802+
}
1803+
17421804
/// <summary>
17431805
/// Convenience function for calculating tangent data for a TTModel.
17441806
/// </summary>

0 commit comments

Comments
 (0)