Skip to content

Commit b14e51f

Browse files
committed
Flow Data Fiesta
1 parent db44bb2 commit b14e51f

File tree

11 files changed

+217
-64
lines changed

11 files changed

+217
-64
lines changed

xivModdingFramework/Models/DataContainers/TTModel.cs

Lines changed: 98 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
using xivModdingFramework.Mods;
2626
using xivModdingFramework.Textures.Enums;
2727
using static xivModdingFramework.Cache.XivCache;
28+
using MathNet.Numerics.LinearAlgebra;
2829

2930
namespace xivModdingFramework.Models.DataContainers
3031
{
@@ -88,6 +89,7 @@ public class TTVertex : ICloneable {
8889
public Vector3 Normal = new Vector3(0, 0, 0);
8990
public Vector3 Binormal = new Vector3(0, 0, 0);
9091
public Vector3 Tangent = new Vector3(0, 0, 0);
92+
public Vector3 FlowDirection = new Vector3(0, 0, 0);
9193

9294
// This is Technically BINORMAL handedness in FFXIV.
9395
// A values of TRUE indicates we need to flip the Tangent when generated. (-1)
@@ -107,6 +109,64 @@ public class TTVertex : ICloneable {
107109
public byte[] BoneIds = new byte[_BONE_ARRAY_LENGTH];
108110
public byte[] Weights = new byte[_BONE_ARRAY_LENGTH];
109111

112+
public Vector3 GetTangentSpaceFlow()
113+
{
114+
var flow = WorldToTangent(FlowDirection.ToArray());
115+
return new Vector3(flow[0], flow[1], 0).Normalized();
116+
}
117+
118+
public float[] WorldToTangent(float[] vector)
119+
{
120+
var mat = Matrix<float>.Build.Dense(3, 3);
121+
122+
var n = Normal.Normalized();
123+
var b = Binormal.Normalized();
124+
var t = Tangent.Normalized();
125+
126+
mat[0, 0] = t[0];
127+
mat[0, 1] = t[1];
128+
mat[0, 2] = t[2];
129+
130+
mat[1, 0] = b[0];
131+
mat[1, 1] = b[1];
132+
mat[1, 2] = b[2];
133+
134+
mat[2, 0] = n[0];
135+
mat[2, 1] = n[1];
136+
mat[2, 2] = n[2];
137+
var vec = Vector<float>.Build.Dense(vector);
138+
139+
var flow = mat * vec;
140+
return flow.AsArray();
141+
}
142+
143+
public float[] TangentToWorld(float[] vector)
144+
{
145+
var mat = Matrix<float>.Build.Dense(3, 3);
146+
147+
var n = Normal.Normalized();
148+
var b = Binormal.Normalized();
149+
var t = Tangent.Normalized();
150+
151+
mat[0, 0] = t[0];
152+
mat[0, 1] = t[1];
153+
mat[0, 2] = t[2];
154+
155+
mat[1, 0] = b[0];
156+
mat[1, 1] = b[1];
157+
mat[1, 2] = b[2];
158+
159+
mat[2, 0] = n[0];
160+
mat[2, 1] = n[1];
161+
mat[2, 2] = n[2];
162+
var vec = Vector<float>.Build.Dense(vector);
163+
164+
mat = mat.Transpose();
165+
166+
var flow = mat * vec;
167+
return flow.AsArray();
168+
}
169+
110170
public static List<TTVertex> CloneVertexList(List<TTVertex> verts)
111171
{
112172
var newVerts = new List<TTVertex>(verts.Count);
@@ -124,6 +184,7 @@ public static List<TTVertex> CloneVertexList(List<TTVertex> verts)
124184
if (a.Normal != b.Normal) return false;
125185
if (a.Binormal != b.Binormal) return false;
126186
if (a.Handedness != b.Handedness) return false;
187+
if (a.FlowDirection != b.FlowDirection) return false;
127188
if (a.UV1 != b.UV1) return false;
128189
if (a.UV2 != b.UV2) return false;
129190
if (a.UV2 != b.UV3) return false;
@@ -1385,7 +1446,7 @@ public uint GetAttributeBitmask(int groupNumber, int partNumber)
13851446
/// </summary>
13861447
/// <param name="filePath"></param>
13871448
/// <returns></returns>
1388-
public static TTModel LoadFromFile(string filePath, Action<bool, string> loggingFunction = null, ModelImportOptions settings = null)
1449+
public static async Task<TTModel> LoadFromFile(string filePath, Action<bool, string> loggingFunction = null, ModelImportOptions settings = null)
13891450
{
13901451
if (loggingFunction == null)
13911452
{
@@ -1583,6 +1644,10 @@ public static TTModel LoadFromFile(string filePath, Action<bool, string> logging
15831644
vertex.Weights[6] = (byte)(Math.Round(reader.GetFloat("bone_7_weight") * 255));
15841645
vertex.Weights[7] = (byte)(Math.Round(reader.GetFloat("bone_8_weight") * 255));
15851646

1647+
1648+
vertex.FlowDirection[0] = reader.GetFloat("flow_u");
1649+
vertex.FlowDirection[1] = reader.GetFloat("flow_v");
1650+
15861651
return vertex;
15871652
});
15881653

@@ -1651,6 +1716,10 @@ public static TTModel LoadFromFile(string filePath, Action<bool, string> logging
16511716
// Convert the model to FFXIV's internal weirdness.
16521717
ModelModifiers.MakeImportReady(model, settings.ShiftImportUV, loggingFunction);
16531718

1719+
await ModelModifiers.CalculateTangents(model, loggingFunction);
1720+
1721+
await ModelModifiers.ConvertFlowData(model, loggingFunction);
1722+
16541723
ModelModifiers.CleanWeights(model, loggingFunction);
16551724

16561725
return model;
@@ -1662,6 +1731,7 @@ private static void MigrateImportDb(SQLiteConnection db)
16621731
Version version = null;
16631732

16641733
bool hasUv3 = false;
1734+
bool hasFlow = false;
16651735
var query = @"PRAGMA table_info(vertices);";
16661736
using (var cmd = new SQLiteCommand(query, db))
16671737
{
@@ -1674,6 +1744,10 @@ private static void MigrateImportDb(SQLiteConnection db)
16741744
{
16751745
hasUv3 = true;
16761746
}
1747+
if (name == "flow_u")
1748+
{
1749+
hasFlow = true;
1750+
}
16771751
}
16781752

16791753
if (!sqlReader.IsClosed)
@@ -1697,6 +1771,20 @@ private static void MigrateImportDb(SQLiteConnection db)
16971771
}
16981772
}
16991773

1774+
if (!hasFlow)
1775+
{
1776+
query = "ALTER TABLE vertices ADD COLUMN flow_u REAL NOT NULL DEFAULT 0;";
1777+
using (var cmd = new SQLiteCommand(query, db))
1778+
{
1779+
cmd.ExecuteScalar();
1780+
}
1781+
query = "ALTER TABLE vertices ADD COLUMN flow_v REAL NOT NULL DEFAULT 0;";
1782+
using (var cmd = new SQLiteCommand(query, db))
1783+
{
1784+
cmd.ExecuteScalar();
1785+
}
1786+
}
1787+
17001788
}
17011789

17021790

@@ -2389,8 +2477,8 @@ public static void SaveFullToFile(string filePath, XivRace race, List<TTModel> m
23892477

23902478
private static void WriteVertex(TTVertex v, SQLiteConnection db, int meshIdx, int partIdx, int vIdx)
23912479
{
2392-
var query = @"insert into vertices ( mesh, part, vertex_id, position_x, position_y, position_z, normal_x, normal_y, normal_z, binormal_x, binormal_y, binormal_z, tangent_x, tangent_y, tangent_z, color_r, color_g, color_b, color_a, color2_r, color2_g, color2_b, color2_a, uv_1_u, uv_1_v, uv_2_u, uv_2_v, bone_1_id, bone_1_weight, bone_2_id, bone_2_weight, bone_3_id, bone_3_weight, bone_4_id, bone_4_weight, bone_5_id, bone_5_weight, bone_6_id, bone_6_weight, bone_7_id, bone_7_weight, bone_8_id, bone_8_weight, uv_3_u, uv_3_v)
2393-
values ($mesh, $part, $vertex_id, $position_x, $position_y, $position_z, $normal_x, $normal_y, $normal_z, $binormal_x, $binormal_y, $binormal_z, $tangent_x, $tangent_y, $tangent_z, $color_r, $color_g, $color_b, $color_a, $color2_r, $color2_g, $color2_b, $color2_a, $uv_1_u, $uv_1_v, $uv_2_u, $uv_2_v, $bone_1_id, $bone_1_weight, $bone_2_id, $bone_2_weight, $bone_3_id, $bone_3_weight, $bone_4_id, $bone_4_weight, $bone_5_id, $bone_5_weight, $bone_6_id, $bone_6_weight, $bone_7_id, $bone_7_weight, $bone_8_id, $bone_8_weight, $uv_3_u, $uv_3_v);";
2480+
var query = @"insert into vertices ( mesh, part, vertex_id, position_x, position_y, position_z, normal_x, normal_y, normal_z, binormal_x, binormal_y, binormal_z, tangent_x, tangent_y, tangent_z, color_r, color_g, color_b, color_a, color2_r, color2_g, color2_b, color2_a, uv_1_u, uv_1_v, uv_2_u, uv_2_v, bone_1_id, bone_1_weight, bone_2_id, bone_2_weight, bone_3_id, bone_3_weight, bone_4_id, bone_4_weight, bone_5_id, bone_5_weight, bone_6_id, bone_6_weight, bone_7_id, bone_7_weight, bone_8_id, bone_8_weight, uv_3_u, uv_3_v, flow_u, flow_v)
2481+
values ($mesh, $part, $vertex_id, $position_x, $position_y, $position_z, $normal_x, $normal_y, $normal_z, $binormal_x, $binormal_y, $binormal_z, $tangent_x, $tangent_y, $tangent_z, $color_r, $color_g, $color_b, $color_a, $color2_r, $color2_g, $color2_b, $color2_a, $uv_1_u, $uv_1_v, $uv_2_u, $uv_2_v, $bone_1_id, $bone_1_weight, $bone_2_id, $bone_2_weight, $bone_3_id, $bone_3_weight, $bone_4_id, $bone_4_weight, $bone_5_id, $bone_5_weight, $bone_6_id, $bone_6_weight, $bone_7_id, $bone_7_weight, $bone_8_id, $bone_8_weight, $uv_3_u, $uv_3_v, $flow_u, $flow_v);";
23942482
using (var cmd = new SQLiteCommand(query, db))
23952483
{
23962484
cmd.Parameters.AddWithValue("part", partIdx);
@@ -2454,6 +2542,11 @@ private static void WriteVertex(TTVertex v, SQLiteConnection db, int meshIdx, in
24542542
cmd.Parameters.AddWithValue("bone_8_id", v.BoneIds[7]);
24552543
cmd.Parameters.AddWithValue("bone_8_weight", v.Weights[7] / 255f);
24562544

2545+
2546+
var flow = v.GetTangentSpaceFlow();
2547+
cmd.Parameters.AddWithValue("flow_u", flow.X);
2548+
cmd.Parameters.AddWithValue("flow_v", flow.Y);
2549+
24572550
cmd.ExecuteScalar();
24582551
}
24592552
}
@@ -2545,7 +2638,7 @@ public void SetFullModelDBMetaData(string filePath, string fullModelName)
25452638
/// </summary>
25462639
/// <param name="rawMdl"></param>
25472640
/// <returns></returns>
2548-
public static TTModel FromRaw(XivMdl rawMdl, Action<bool, string> loggingFunction = null)
2641+
public static async Task<TTModel> FromRaw(XivMdl rawMdl, Action<bool, string> loggingFunction = null)
25492642
{
25502643
if(rawMdl == null)
25512644
{
@@ -2578,6 +2671,7 @@ public static TTModel FromRaw(XivMdl rawMdl, Action<bool, string> loggingFunctio
25782671

25792672
ttModel.UVState = UVAddressingSpace.SE_Space;
25802673

2674+
await ModelModifiers.CalculateTangents(ttModel);
25812675
return ttModel;
25822676
}
25832677

xivModdingFramework/Models/DataContainers/VertexData.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,12 @@ public class VertexData
6767
/// <summary>
6868
/// The vertex Tangent data in Vector3 format (X, Y, Z)
6969
/// </summary>
70-
public Vector3Collection Tangents { get; set; } = new Vector3Collection();
70+
public Vector3Collection FlowDirections { get; set; } = new Vector3Collection();
7171

7272
/// <summary>
7373
/// The vertex BiNormal Handedness data in bytes
7474
/// </summary>
75-
public List<byte> TangentHandedness { get; set; } = new List<byte>();
75+
public List<byte> FlowHandedness { get; set; } = new List<byte>();
7676

7777
/// <summary>
7878
/// The vertex color data in Byte4 format (R, G, B, A)

xivModdingFramework/Models/Enums/VertexUsageType.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public enum VertexUsageType
2626
BoneIndex = 0x2,
2727
Normal = 0x3,
2828
TextureCoordinate = 0x4,
29-
Tangent = 0x5,
29+
Flow = 0x5,
3030
Binormal = 0x6,
3131
Color = 0x7
3232
}

xivModdingFramework/Models/FileTypes/Mdl.cs

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ public static async Task<TTModel> GetTTModel(IItemModel item, XivRace race, stri
300300
{
301301
var mdlPath = await GetMdlPath(item, race, submeshId, tx);
302302
var mdl = await GetXivMdl(mdlPath, getOriginal, tx);
303-
var ttModel = TTModel.FromRaw(mdl);
303+
var ttModel = await TTModel.FromRaw(mdl);
304304
return ttModel;
305305
}
306306

@@ -314,14 +314,14 @@ public static async Task<TTModel> GetTTModel(IItemModel item, XivRace race, stri
314314
public static async Task<TTModel> GetTTModel(string mdlPath, bool getOriginal = false, ModTransaction tx = null)
315315
{
316316
var mdl = await GetXivMdl(mdlPath, getOriginal, tx);
317-
var ttModel = TTModel.FromRaw(mdl);
317+
var ttModel = await TTModel.FromRaw(mdl);
318318
return ttModel;
319319
}
320320

321-
public static TTModel GetTTModel(byte[] mdlData, string mdlPath = "")
321+
public static async Task<TTModel> GetTTModel(byte[] mdlData, string mdlPath = "")
322322
{
323323
var mdl = GetXivMdl(mdlData, mdlPath);
324-
var ttModel = TTModel.FromRaw(mdl);
324+
var ttModel = await TTModel.FromRaw(mdl);
325325
return ttModel;
326326
}
327327

@@ -1849,7 +1849,7 @@ public static async Task<long> ImportModel(string externalFile, string internalF
18491849
{
18501850
// Kind of clunky to have to convert this back off bytes, but w/e.
18511851
// This codepath is basically unused at this point anyways.
1852-
var ttm = Mdl.GetTTModel(bytes, internalFile);
1852+
var ttm = await Mdl.GetTTModel(bytes, internalFile);
18531853
await FillMissingMaterials(ttm, options.ReferenceItem, options.SourceApplication, tx);
18541854
}
18551855

@@ -1998,7 +1998,7 @@ await Task.Run(async () =>
19981998
loggingFunction(false, "Waiting on user...");
19991999

20002000
// Bool says whether or not we should continue.
2001-
var oldModel = TTModel.FromRaw(originalMdl);
2001+
var oldModel = await TTModel.FromRaw(originalMdl);
20022002
bool cont = await options.IntermediaryFunction(ttModel, oldModel);
20032003
if (!cont)
20042004
{
@@ -2051,14 +2051,14 @@ public static async Task<TTModel> LoadExternalModel(string externalPath, ModelIm
20512051
{
20522052
// Raw already converted DB file, just load it.
20532053
loggingFunction(false, "Loading intermediate file...");
2054-
ttModel = TTModel.LoadFromFile(externalPath, loggingFunction, options);
2054+
ttModel = await TTModel.LoadFromFile(externalPath, loggingFunction, options);
20552055
}
20562056
else
20572057
{
20582058
// External Importer converts the file to .db format.
20592059
var dbFile = await RunExternalImporter(suffix, externalPath, loggingFunction);
20602060
loggingFunction(false, "Loading intermediate file...");
2061-
ttModel = TTModel.LoadFromFile(dbFile, loggingFunction, options);
2061+
ttModel = await TTModel.LoadFromFile(dbFile, loggingFunction, options);
20622062
}
20632063

20642064
if(ttModel == null)
@@ -2443,10 +2443,6 @@ public static byte[] MakeUncompressedMdlFile(TTModel ttModel, XivMdl ogMdl, Acti
24432443
{
24442444
var mdlVersion = ttModel.MdlVersion > 0 ? ttModel.MdlVersion : ogMdl.MdlVersion;
24452445

2446-
// Always calculate tangents as the final step, to ensure no more UV modification is happening.
2447-
// The tangent function will internally shift the referenced UVs into SE-UV Addressing space as needed.
2448-
ModelModifiers.CalculateTangents(ttModel, loggingFunction, true);
2449-
24502446
ttModel.MdlVersion = mdlVersion;
24512447

24522448
byte _LoDCount = 1;
@@ -2463,7 +2459,7 @@ public static byte[] MakeUncompressedMdlFile(TTModel ttModel, XivMdl ogMdl, Acti
24632459
loggingFunction = NoOp;
24642460
}
24652461

2466-
var useTangents = ttModel.AnisotropicLightingEnabled;
2462+
var useFlowData = ttModel.AnisotropicLightingEnabled;
24672463
try
24682464
{
24692465
var usageInfo = ttModel.GetUsageInfo();
@@ -2487,7 +2483,7 @@ public static byte[] MakeUncompressedMdlFile(TTModel ttModel, XivMdl ogMdl, Acti
24872483
{
24882484
vertexSize += 4;
24892485
}
2490-
if (useTangents)
2486+
if (useFlowData)
24912487
{
24922488
vertexSize += 4;
24932489
}
@@ -2610,14 +2606,14 @@ public static byte[] MakeUncompressedMdlFile(TTModel ttModel, XivMdl ogMdl, Acti
26102606
});
26112607

26122608
// Optional/Situational Elements
2613-
if (upgradePrecision && useTangents)
2609+
if (upgradePrecision && useFlowData)
26142610
{
26152611

26162612
AddVertexHeader(source, new VertexDataStruct()
26172613
{
26182614
DataBlock = 1,
26192615
DataType = VertexDataType.Ubyte4n,
2620-
DataUsage = VertexUsageType.Tangent
2616+
DataUsage = VertexUsageType.Flow
26212617
});
26222618
}
26232619

@@ -3978,9 +3974,10 @@ private static bool WriteVectorData(List<byte> buffer, Dictionary<VertexUsageTyp
39783974
value = v.Binormal;
39793975
handedness = v.Handedness;
39803976
break;
3981-
case VertexUsageType.Tangent:
3982-
value = v.Tangent;
3983-
handedness = v.Handedness;
3977+
case VertexUsageType.Flow:
3978+
value = v.FlowDirection;
3979+
// Unused
3980+
handedness = true;
39843981
break;
39853982
default:
39863983
return false;
@@ -4082,7 +4079,7 @@ private static int WriteVertex(VertexByteData importData, Dictionary<VertexUsage
40824079

40834080
WriteVectorData(importData.VertexData1, vertexInfoList, VertexUsageType.Normal, v);
40844081
WriteVectorData(importData.VertexData1, vertexInfoList, VertexUsageType.Binormal, v);
4085-
WriteVectorData(importData.VertexData1, vertexInfoList, VertexUsageType.Tangent, v);
4082+
WriteVectorData(importData.VertexData1, vertexInfoList, VertexUsageType.Flow, v);
40864083

40874084

40884085
if (vertexInfoList.ContainsKey(VertexUsageType.Color))
@@ -4200,7 +4197,7 @@ public static async Task<bool> CheckSkinAssignment(string mdlPath, ModTransactio
42004197
var modlist = await tx.GetModList();
42014198

42024199
var ogMdl = await GetXivMdl(mdlPath, false, tx);
4203-
var ttMdl = TTModel.FromRaw(ogMdl);
4200+
var ttMdl = await TTModel.FromRaw(ogMdl);
42044201

42054202
bool anyChanges = false;
42064203
anyChanges = SkinCheckBibo(ttMdl, index);
@@ -4783,7 +4780,7 @@ public static async Task<long> CopyModel(string originalPath, string newPath, st
47834780
var modlist = await tx.GetModList();
47844781

47854782
var xMdl = await GetXivMdl(originalPath, false, tx);
4786-
var model = TTModel.FromRaw(xMdl);
4783+
var model = await TTModel.FromRaw(xMdl);
47874784

47884785

47894786
if (model == null)
@@ -4974,10 +4971,10 @@ public static async Task<long> MergeModels(string primaryModel, string mergeIn,
49744971
var modlist = await tx.GetModList();
49754972

49764973
var xMdl = await GetXivMdl(mergeIn, false, tx);
4977-
var mergeInModel = TTModel.FromRaw(xMdl);
4974+
var mergeInModel = await TTModel.FromRaw(xMdl);
49784975

49794976
var xMdl2 = await GetXivMdl(primaryModel, false, tx);
4980-
var mainModel = TTModel.FromRaw(xMdl2);
4977+
var mainModel = await TTModel.FromRaw(xMdl2);
49814978

49824979

49834980
if (mergeInModel == null)
@@ -5255,7 +5252,7 @@ public static async Task ExportAllTextures(TTModel model, string targetFolder, i
52555252
{0x2, VertexUsageType.BoneIndex },
52565253
{0x3, VertexUsageType.Normal },
52575254
{0x4, VertexUsageType.TextureCoordinate },
5258-
{0x5, VertexUsageType.Tangent },
5255+
{0x5, VertexUsageType.Flow },
52595256
{0x6, VertexUsageType.Binormal },
52605257
{0x7, VertexUsageType.Color }
52615258
};

0 commit comments

Comments
 (0)