Skip to content

Commit c7f44a7

Browse files
committed
- Conversion of Shader byte array parameters to their proper float type.
- Addition of [Face] and [FaceBright] presets for the Hair shader. - These are the presets used for the [etc] materials for faces, which use Tattoo Color/Limbal Ring color instead of Hair Highlight Color.
1 parent 71355bd commit c7f44a7

File tree

2 files changed

+127
-99
lines changed

2 files changed

+127
-99
lines changed

xivModdingFramework/Materials/DataContainers/XivMtrl.cs

Lines changed: 76 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -176,16 +176,10 @@ public ushort ShaderParameterDataSize {
176176
get {
177177
var size = 0;
178178
ShaderParameterList.ForEach(x => {
179-
size += x.Bytes.Count;
179+
size += x.Args.Count * 4;
180180
}
181181
);
182182

183-
if(size % 8 != 0)
184-
{
185-
var padding = 8 - (size % 8);
186-
size += padding;
187-
}
188-
189183
return (ushort)size;
190184
}
191185
set
@@ -355,6 +349,26 @@ public ShaderInfo GetShaderInfo()
355349
if(GetTextureUsage(XivTexType.Skin) == null)
356350
{
357351
info.Preset = MtrlShaderPreset.Face;
352+
}
353+
} else if(info.Shader == MtrlShader.Hair)
354+
{
355+
if(GetTextureUsage(XivTexType.Other) != null)
356+
{
357+
info.Preset = MtrlShaderPreset.Face;
358+
var mul = 1.4f;
359+
var param = ShaderParameterList.FirstOrDefault(x => x.ParameterID == MtrlShaderParameterId.SkinColor);
360+
if(param != null)
361+
{
362+
mul = param.Args[0];
363+
}
364+
365+
// Limbal ring faces (Au Ra) use a 3.0 multiplier for brightness.
366+
if(mul == 3.0)
367+
{
368+
info.Preset = MtrlShaderPreset.FaceBright;
369+
}
370+
371+
358372
}
359373
}
360374

@@ -735,6 +749,12 @@ private void RegenerateTextureUsageList(ShaderInfo info)
735749
// These shaders do not use the texture usage list at all.
736750
if (info.Shader == MtrlShader.Furniture || info.Shader == MtrlShader.DyeableFurniture || info.Shader == MtrlShader.Iris || info.Shader == MtrlShader.Hair)
737751
{
752+
if(info.Shader == MtrlShader.Hair && info.Preset != MtrlShaderPreset.Default)
753+
{
754+
// The facial hair shaders use this texture usage value to pipe in
755+
// Tattoo/Limbal color instead of Hair Highlight color.
756+
SetTextureUsage(XivTexType.Other);
757+
}
738758
return;
739759
}
740760

@@ -782,54 +802,65 @@ private void RegenerateTextureUsageList(ShaderInfo info)
782802
/// </summary>
783803
private void RegenerateShaderParameterList(ShaderInfo info)
784804
{
785-
var args = new List<MtrlShaderParameterId>();
805+
var args = new Dictionary<MtrlShaderParameterId, List<float>>();
786806

787-
args.Add(MtrlShaderParameterId.Common1);
788-
args.Add(MtrlShaderParameterId.Common2);
807+
args.Add(MtrlShaderParameterId.Common1, null);
808+
args.Add(MtrlShaderParameterId.Common2, null);
789809

790810
if (info.Shader == MtrlShader.Skin)
791811
{
792-
args.Add(MtrlShaderParameterId.SkinColor);
793-
args.Add(MtrlShaderParameterId.SkinOutline);
794-
args.Add(MtrlShaderParameterId.SkinUnknown1);
795-
args.Add(MtrlShaderParameterId.SkinUnknown2);
796-
args.Add(MtrlShaderParameterId.SkinUnknown3);
797-
args.Add(MtrlShaderParameterId.RacialSkin1);
798-
args.Add(MtrlShaderParameterId.RacialSkin2);
799-
args.Add(MtrlShaderParameterId.Reflection1);
812+
args.Add(MtrlShaderParameterId.SkinColor, null);
813+
args.Add(MtrlShaderParameterId.SkinOutline, null);
814+
args.Add(MtrlShaderParameterId.SkinUnknown1, null);
815+
args.Add(MtrlShaderParameterId.SkinUnknown2, null);
816+
args.Add(MtrlShaderParameterId.SkinUnknown3, null);
817+
args.Add(MtrlShaderParameterId.RacialSkin1, null);
818+
args.Add(MtrlShaderParameterId.RacialSkin2, null);
819+
args.Add(MtrlShaderParameterId.Reflection1, null);
800820

801821
if (info.Preset == MtrlShaderPreset.Face)
802822
{
803-
args.Add(MtrlShaderParameterId.Face1);
823+
args.Add(MtrlShaderParameterId.Face1, null);
804824
}
805825
}
806826
else if (info.Shader == MtrlShader.Standard || info.Shader == MtrlShader.Glass)
807827
{
808-
args.Add(MtrlShaderParameterId.Equipment1);
809-
args.Add(MtrlShaderParameterId.Reflection1);
828+
args.Add(MtrlShaderParameterId.Equipment1, null);
829+
args.Add(MtrlShaderParameterId.Reflection1, null);
810830
}
811831
else if (info.Shader == MtrlShader.Iris)
812832
{
813-
args.Add(MtrlShaderParameterId.Equipment1);
814-
args.Add(MtrlShaderParameterId.Reflection1);
815-
args.Add(MtrlShaderParameterId.RacialSkin1);
816-
args.Add(MtrlShaderParameterId.SkinColor);
817-
args.Add(MtrlShaderParameterId.SkinOutline);
833+
args.Add(MtrlShaderParameterId.Equipment1, null);
834+
args.Add(MtrlShaderParameterId.Reflection1, null);
835+
args.Add(MtrlShaderParameterId.RacialSkin1, null);
836+
args.Add(MtrlShaderParameterId.SkinColor, null);
837+
args.Add(MtrlShaderParameterId.SkinOutline, null);
818838
}
819839
else if(info.Shader == MtrlShader.Hair)
820840
{
821-
args.Add(MtrlShaderParameterId.Equipment1);
822-
args.Add(MtrlShaderParameterId.Reflection1);
823-
args.Add(MtrlShaderParameterId.SkinColor);
824-
args.Add(MtrlShaderParameterId.SkinOutline);
825-
args.Add(MtrlShaderParameterId.Hair1);
826-
args.Add(MtrlShaderParameterId.Hair2);
841+
args.Add(MtrlShaderParameterId.Equipment1, null);
842+
args.Add(MtrlShaderParameterId.Reflection1, null);
843+
args.Add(MtrlShaderParameterId.SkinColor, null);
844+
args.Add(MtrlShaderParameterId.SkinOutline, null);
845+
args.Add(MtrlShaderParameterId.Hair1, null);
846+
args.Add(MtrlShaderParameterId.Hair2, null);
847+
848+
if (info.Preset == MtrlShaderPreset.FaceBright)
849+
{
850+
// Limbals use a 3x skin color modifier.
851+
args[MtrlShaderParameterId.SkinColor] = new List<float>() { 3f, 3f, 3f };
852+
}
827853
}
828854

829855

830856
// Regenerate the list.
831857
ShaderParameterList.Clear();
832-
args.ForEach(x => SetShaderParameter(x));
858+
//args.ForEach(x => SetShaderParameter(x));
859+
foreach(var kv in args)
860+
{
861+
// Nulls use defaults.
862+
SetShaderParameter(kv.Key, kv.Value);
863+
}
833864
}
834865

835866

@@ -848,7 +879,7 @@ private ShaderParameterStruct GetShaderParameter(MtrlShaderParameterId parameter
848879
/// </summary>
849880
/// <param name="parameterId"></param>
850881
/// <param name="data"></param>
851-
private void SetShaderParameter(MtrlShaderParameterId parameterId, List<byte> data = null)
882+
private void SetShaderParameter(MtrlShaderParameterId parameterId, List<float> data = null)
852883
{
853884

854885

@@ -859,7 +890,7 @@ private void SetShaderParameter(MtrlShaderParameterId parameterId, List<byte> da
859890
// Only overwrite if we were given explicit data.
860891
if (value != null && data != null)
861892
{
862-
value.Bytes = data;
893+
value.Args = data;
863894
}
864895
}
865896
catch (Exception ex)
@@ -872,7 +903,7 @@ private void SetShaderParameter(MtrlShaderParameterId parameterId, List<byte> da
872903
ShaderParameterList.Add(new ShaderParameterStruct
873904
{
874905
ParameterID = parameterId,
875-
Bytes = data
906+
Args = data
876907
});
877908
}
878909
}
@@ -1317,8 +1348,7 @@ public class ShaderParameterStruct
13171348

13181349
public short Size;
13191350

1320-
public List<byte> Bytes;
1321-
public List<uint> Args;
1351+
public List<float> Args;
13221352
}
13231353

13241354
/// <summary>
@@ -1360,10 +1390,11 @@ public enum MtrlShader
13601390
// Knows how to build.
13611391
public enum MtrlShaderPreset
13621392
{
1363-
Default,
1364-
DiffuseMulti,
1393+
Default,
1394+
DiffuseMulti,
13651395
DiffuseSpecular,
1366-
Face,
1396+
Face,
1397+
FaceBright,
13671398
}
13681399

13691400
/// <summary>
@@ -1520,6 +1551,10 @@ public static List<MtrlShaderPreset> GetAvailablePresets(MtrlShader shader)
15201551
} else if(shader == MtrlShader.Skin)
15211552
{
15221553
presets.Add(MtrlShaderPreset.Face);
1554+
} else if(shader == MtrlShader.Hair)
1555+
{
1556+
presets.Add(MtrlShaderPreset.Face);
1557+
presets.Add(MtrlShaderPreset.FaceBright);
15231558
}
15241559

15251560
return presets;

xivModdingFramework/Materials/FileTypes/Mtrl.cs

Lines changed: 51 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -106,48 +106,43 @@ public XivDataFile DataFile
106106
{ XivTexType.Diffuse, new TextureUsageStruct() { TextureType = 3054951514, Unknown = 1611594207 } },
107107
{ XivTexType.Specular, new TextureUsageStruct() { TextureType = 3367837167, Unknown = 2687453224 } },
108108
{ XivTexType.Skin, new TextureUsageStruct() { TextureType = 940355280, Unknown = 735790577 } },
109+
{ XivTexType.Other, new TextureUsageStruct() { TextureType = 612525193, Unknown = 1851494160 } },
110+
}; // Probably want to key this off a custom enum soon if we keep finding additional texture usage values.
111+
112+
113+
// Shader Parameter defaults. For most of them they seem to be used as multipliers.
114+
public static Dictionary<MtrlShaderParameterId, List<float>> ShaderParameterValues = new Dictionary<MtrlShaderParameterId, List<float>>() {
115+
{ MtrlShaderParameterId.Common1, new List<float>(){ 0.5f } },
116+
{ MtrlShaderParameterId.Common2, new List<float>(){ 1f } },
117+
{ MtrlShaderParameterId.SkinColor, new List<float>(){ 1.4f, 1.4f, 1.4f } }, // Direct R/G/B Multiplier. 3.0 for Limbal rings.
118+
{ MtrlShaderParameterId.Reflection1, new List<float>(){ 1f } },
119+
{ MtrlShaderParameterId.SkinOutline, new List<float>(){ 3f } },
120+
{ MtrlShaderParameterId.RacialSkin1, new List<float>(){ 0.02f, 0.02f, 0.02f } },
121+
{ MtrlShaderParameterId.SkinUnknown1, new List<float>(){ 0.4f, 0.4f, 0.4f } },
122+
{ MtrlShaderParameterId.SkinUnknown2, new List<float>(){ 0f, 0f, 0f } },
123+
{ MtrlShaderParameterId.RacialSkin2, new List<float>(){ 65f, 100f } },
124+
{ MtrlShaderParameterId.SkinUnknown3, new List<float>(){ 63f } },
125+
{ MtrlShaderParameterId.Equipment1, new List<float>(){ 0f } },
126+
{ MtrlShaderParameterId.Face1, new List<float>(){ 32f } },
127+
{ MtrlShaderParameterId.Hair1, new List<float>(){ 0.35f } },
128+
{ MtrlShaderParameterId.Hair2, new List<float>(){ 0.5f } },
129+
130+
131+
{ MtrlShaderParameterId.Furniture1, new List<float>(){ 1f, 1f, 1f } },
132+
{ MtrlShaderParameterId.Furniture2, new List<float>(){ 1f, 1f, 1f } },
133+
{ MtrlShaderParameterId.Furniture3, new List<float>(){ 0f, 0f, 0f } },
134+
{ MtrlShaderParameterId.Furniture4, new List<float>(){ 1f } },
135+
{ MtrlShaderParameterId.Furniture5, new List<float>(){ 0.15f } },
136+
{ MtrlShaderParameterId.Furniture6, new List<float>(){ 0.15f } },
137+
{ MtrlShaderParameterId.Furniture7, new List<float>(){ 1f } },
138+
{ MtrlShaderParameterId.Furniture8, new List<float>(){ 1f } },
139+
{ MtrlShaderParameterId.Furniture9, new List<float>(){ 1f } },
140+
{ MtrlShaderParameterId.Furniture10, new List<float>(){ 1f, 1f, 1f } },
141+
{ MtrlShaderParameterId.Furniture11, new List<float>(){ 1f, 1f, 1f } },
142+
{ MtrlShaderParameterId.Furniture12, new List<float>(){ 1f, 1f, 1f } },
143+
{ MtrlShaderParameterId.Furniture13, new List<float>(){ 0f, 0f, 0f } },
109144
};
110145

111-
112-
// References to the additional shader data at the end of MTRL files.
113-
// Stored by ID, though unknown yet what the IDs correspond to.
114-
// I suspect the IDs are used for piping additional maps/values to the shader, such as cube maps for reflection
115-
// and skin/hair/iris color, etc. -Sel
116-
// The actual byte array values do change a bit, but thus far I haven't been able to notice differences when they're changed.
117-
public static Dictionary<MtrlShaderParameterId, List<byte>> ShaderParameterValues = new Dictionary<MtrlShaderParameterId, List<byte>>() {
118-
{ MtrlShaderParameterId.Common1, new List<byte>(){ 0,0,0,63 } },
119-
{ MtrlShaderParameterId.Common2, new List<byte>(){ 0,0,128,63 } },
120-
{ MtrlShaderParameterId.SkinColor, new List<byte>(){ 51, 51, 179, 63, 51, 51, 179, 63, 51, 51, 179, 63 } },
121-
{ MtrlShaderParameterId.Reflection1, new List<byte>(){ 0,0,128,63 } },
122-
{ MtrlShaderParameterId.SkinOutline, new List<byte>(){ 0,0,64,64 } },
123-
{ MtrlShaderParameterId.RacialSkin1, new List<byte>(){ 10, 215, 163, 60, 10, 215, 163, 60, 10, 215, 163, 60 } },
124-
{ MtrlShaderParameterId.SkinUnknown1, new List<byte>(){ 205, 204, 204, 62, 205, 204, 204, 62, 205, 204, 204, 62 } },
125-
{ MtrlShaderParameterId.SkinUnknown2, new List<byte>(){ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
126-
{ MtrlShaderParameterId.RacialSkin2, new List<byte>(){ 0, 0, 130, 66, 0, 0, 200, 66 } },
127-
{ MtrlShaderParameterId.SkinUnknown3, new List<byte>(){ 0, 0, 124, 66 } },
128-
{ MtrlShaderParameterId.Equipment1, new List<byte>(){ 0, 0, 0, 0 } },
129-
{ MtrlShaderParameterId.Face1, new List<byte>(){ 0, 0, 0, 66 } },
130-
{ MtrlShaderParameterId.Hair1, new List<byte>(){ 51, 51, 179, 62 } },
131-
{ MtrlShaderParameterId.Hair2, new List<byte>(){ 0, 0, 0, 63 } },
132-
133-
134-
{ MtrlShaderParameterId.Furniture1, new List<byte>(){ 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63 } },
135-
{ MtrlShaderParameterId.Furniture2, new List<byte>(){ 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63 } },
136-
{ MtrlShaderParameterId.Furniture3, new List<byte>(){ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
137-
{ MtrlShaderParameterId.Furniture4, new List<byte>(){ 0, 0, 128, 63 } },
138-
{ MtrlShaderParameterId.Furniture5, new List<byte>(){ 143, 194, 117, 60 } },
139-
{ MtrlShaderParameterId.Furniture6, new List<byte>(){ 143, 194, 117, 60 } },
140-
{ MtrlShaderParameterId.Furniture7, new List<byte>(){ 0, 0, 128, 63 } },
141-
{ MtrlShaderParameterId.Furniture8, new List<byte>(){ 0, 0, 128, 63 } },
142-
{ MtrlShaderParameterId.Furniture9, new List<byte>(){ 0, 0, 128, 63 } },
143-
{ MtrlShaderParameterId.Furniture10, new List<byte>(){ 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63 } },
144-
{ MtrlShaderParameterId.Furniture11, new List<byte>(){ 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63 } },
145-
{ MtrlShaderParameterId.Furniture12, new List<byte>(){ 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63 } },
146-
{ MtrlShaderParameterId.Furniture13, new List<byte>(){ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 63 } },
147-
};
148-
149-
150-
151146
/// <summary>
152147
/// Gets the MTRL data for the given item
153148
/// </summary>
@@ -517,22 +512,19 @@ await Task.Run((Func<Task>)(async () =>
517512
{
518513
var offset = shaderParam.Offset;
519514
var size = shaderParam.Size;
520-
shaderParam.Bytes = new List<byte>();
521-
shaderParam.Args = new List<uint>();
515+
shaderParam.Args = new List<float>();
522516
if (bytesRead + size <= originalShaderParameterDataSize)
523517
{
524518
for (var idx = offset; idx < offset + size; idx+=4)
525519
{
526-
var arg = br.ReadUInt32();
520+
var arg = br.ReadSingle();
527521
shaderParam.Args.Add(arg);
528522
bytesRead += 4;
529-
shaderParam.Bytes.AddRange(BitConverter.GetBytes(arg));
530523
}
531524
} else
532525
{
533526
// Just use a blank array if we have missing/invalid shader data.
534-
shaderParam.Bytes = new List<byte>(new byte[size]);
535-
shaderParam.Args = new List<uint>(new uint[size / 4]);
527+
shaderParam.Args = new List<float>(new float[size / 4]);
536528
}
537529
}
538530

@@ -784,16 +776,17 @@ public byte[] CreateMtrlFile(XivMtrl xivMtrl, IItem item)
784776
}
785777

786778
var offset = 0;
787-
foreach (var dataStruct2 in xivMtrl.ShaderParameterList)
779+
foreach (var parameter in xivMtrl.ShaderParameterList)
788780
{
789781
// Ensure we're writing correctly calculated data.
790-
dataStruct2.Offset = (short) offset;
791-
dataStruct2.Size = (short) dataStruct2.Bytes.Count;
792-
offset += dataStruct2.Size;
793-
794-
mtrlBytes.AddRange(BitConverter.GetBytes((uint)dataStruct2.ParameterID));
795-
mtrlBytes.AddRange(BitConverter.GetBytes(dataStruct2.Offset));
796-
mtrlBytes.AddRange(BitConverter.GetBytes(dataStruct2.Size));
782+
parameter.Offset = (short) offset;
783+
parameter.Size = (short)parameter.Args.Count;
784+
offset += parameter.Size * 4;
785+
short byteSize = (short)(parameter.Size * 4);
786+
787+
mtrlBytes.AddRange(BitConverter.GetBytes((uint)parameter.ParameterID));
788+
mtrlBytes.AddRange(BitConverter.GetBytes(parameter.Offset));
789+
mtrlBytes.AddRange(BitConverter.GetBytes(byteSize));
797790
}
798791

799792
foreach (var parameterStruct in xivMtrl.TextureDescriptorList)
@@ -809,9 +802,10 @@ public byte[] CreateMtrlFile(XivMtrl xivMtrl, IItem item)
809802
var shaderBytes = new List<byte>();
810803
foreach (var shaderParam in xivMtrl.ShaderParameterList)
811804
{
812-
//shaderBytes.AddRange(Mtrl.ShaderParameterValues[shaderParam.ParameterID]);
813-
//shaderBytes.AddRange(new byte[shaderParam.Bytes.Count]);
814-
shaderBytes.AddRange(shaderParam.Bytes);
805+
foreach (var f in shaderParam.Args)
806+
{
807+
shaderBytes.AddRange(BitConverter.GetBytes(f));
808+
}
815809
}
816810

817811
// Pad out if we're missing anything.
@@ -821,7 +815,6 @@ public byte[] CreateMtrlFile(XivMtrl xivMtrl, IItem item)
821815
}
822816
mtrlBytes.AddRange(shaderBytes);
823817

824-
//mtrlBytes.AddRange(xivMtrl.AdditionalData);
825818

826819

827820
// Backfill the actual file size data.

0 commit comments

Comments
 (0)