Some formatting and naming changes, splitting files and some minor improvements.

This commit is contained in:
Ottermandias 2023-02-23 14:48:46 +01:00
parent 1e471551d4
commit a2b62a8b6a
13 changed files with 928 additions and 997 deletions

View file

@ -0,0 +1,90 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace Penumbra.GameData.Files;
public partial class MtrlFile
{
public unsafe struct ColorDyeSet
{
public struct Row
{
private ushort _data;
public ushort Template
{
get => (ushort)(_data >> 5);
set => _data = (ushort)((_data & 0x1F) | (value << 5));
}
public bool Diffuse
{
get => (_data & 0x01) != 0;
set => _data = (ushort)(value ? _data | 0x01 : _data & 0xFFFE);
}
public bool Specular
{
get => (_data & 0x02) != 0;
set => _data = (ushort)(value ? _data | 0x02 : _data & 0xFFFD);
}
public bool Emissive
{
get => (_data & 0x04) != 0;
set => _data = (ushort)(value ? _data | 0x04 : _data & 0xFFFB);
}
public bool Gloss
{
get => (_data & 0x08) != 0;
set => _data = (ushort)(value ? _data | 0x08 : _data & 0xFFF7);
}
public bool SpecularStrength
{
get => (_data & 0x10) != 0;
set => _data = (ushort)(value ? _data | 0x10 : _data & 0xFFEF);
}
}
public struct RowArray : IEnumerable<Row>
{
public const int NumRows = 16;
private fixed ushort _rowData[NumRows];
public ref Row this[int i]
{
get
{
fixed (ushort* ptr = _rowData)
{
return ref ((Row*)ptr)[i];
}
}
}
public IEnumerator<Row> GetEnumerator()
{
for (var i = 0; i < NumRows; ++i)
yield return this[i];
}
IEnumerator IEnumerable.GetEnumerator()
=> GetEnumerator();
public ReadOnlySpan<byte> AsBytes()
{
fixed (ushort* ptr = _rowData)
{
return new ReadOnlySpan<byte>(ptr, NumRows * sizeof(ushort));
}
}
}
public RowArray Rows;
public string Name;
public ushort Index;
}
}

View file

@ -0,0 +1,135 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Numerics;
namespace Penumbra.GameData.Files;
public partial class MtrlFile
{
public unsafe struct ColorSet
{
public struct Row
{
public const int Size = 32;
private fixed ushort _data[16];
public Vector3 Diffuse
{
get => new(ToFloat(0), ToFloat(1), ToFloat(2));
set
{
_data[0] = FromFloat(value.X);
_data[1] = FromFloat(value.Y);
_data[2] = FromFloat(value.Z);
}
}
public Vector3 Specular
{
get => new(ToFloat(4), ToFloat(5), ToFloat(6));
set
{
_data[4] = FromFloat(value.X);
_data[5] = FromFloat(value.Y);
_data[6] = FromFloat(value.Z);
}
}
public Vector3 Emissive
{
get => new(ToFloat(8), ToFloat(9), ToFloat(10));
set
{
_data[8] = FromFloat(value.X);
_data[9] = FromFloat(value.Y);
_data[10] = FromFloat(value.Z);
}
}
public Vector2 MaterialRepeat
{
get => new(ToFloat(12), ToFloat(15));
set
{
_data[12] = FromFloat(value.X);
_data[15] = FromFloat(value.Y);
}
}
public Vector2 MaterialSkew
{
get => new(ToFloat(13), ToFloat(14));
set
{
_data[13] = FromFloat(value.X);
_data[14] = FromFloat(value.Y);
}
}
public float SpecularStrength
{
get => ToFloat(3);
set => _data[3] = FromFloat(value);
}
public float GlossStrength
{
get => ToFloat(7);
set => _data[7] = FromFloat(value);
}
public ushort TileSet
{
get => (ushort)(ToFloat(11) * 64f);
set => _data[11] = FromFloat(value / 64f);
}
private float ToFloat(int idx)
=> (float)BitConverter.UInt16BitsToHalf(_data[idx]);
private static ushort FromFloat(float x)
=> BitConverter.HalfToUInt16Bits((Half)x);
}
public struct RowArray : IEnumerable<Row>
{
public const int NumRows = 16;
private fixed byte _rowData[NumRows * Row.Size];
public ref Row this[int i]
{
get
{
fixed (byte* ptr = _rowData)
{
return ref ((Row*)ptr)[i];
}
}
}
public IEnumerator<Row> GetEnumerator()
{
for (var i = 0; i < NumRows; ++i)
yield return this[i];
}
IEnumerator IEnumerable.GetEnumerator()
=> GetEnumerator();
public ReadOnlySpan<byte> AsBytes()
{
fixed (byte* ptr = _rowData)
{
return new ReadOnlySpan<byte>(ptr, NumRows * Row.Size);
}
}
}
public RowArray Rows;
public string Name;
public ushort Index;
public bool HasRows;
}
}

View file

@ -1,4 +1,3 @@
using System;
using System.IO;
using System.Linq;
using System.Text;

View file

@ -1,9 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text;
using Lumina.Data.Parsing;
using Lumina.Extensions;
@ -13,262 +11,10 @@ namespace Penumbra.GameData.Files;
public partial class MtrlFile : IWritable
{
public struct UvSet
{
public string Name;
public ushort Index;
}
public unsafe struct ColorSet
{
public struct Row
{
public const int Size = 32;
private fixed ushort _data[16];
public Vector3 Diffuse
{
get => new(ToFloat(0), ToFloat(1), ToFloat(2));
set
{
_data[0] = FromFloat(value.X);
_data[1] = FromFloat(value.Y);
_data[2] = FromFloat(value.Z);
}
}
public Vector3 Specular
{
get => new(ToFloat(4), ToFloat(5), ToFloat(6));
set
{
_data[4] = FromFloat(value.X);
_data[5] = FromFloat(value.Y);
_data[6] = FromFloat(value.Z);
}
}
public Vector3 Emissive
{
get => new(ToFloat(8), ToFloat(9), ToFloat(10));
set
{
_data[8] = FromFloat(value.X);
_data[9] = FromFloat(value.Y);
_data[10] = FromFloat(value.Z);
}
}
public Vector2 MaterialRepeat
{
get => new(ToFloat(12), ToFloat(15));
set
{
_data[12] = FromFloat(value.X);
_data[15] = FromFloat(value.Y);
}
}
public Vector2 MaterialSkew
{
get => new(ToFloat(13), ToFloat(14));
set
{
_data[13] = FromFloat(value.X);
_data[14] = FromFloat(value.Y);
}
}
public float SpecularStrength
{
get => ToFloat(3);
set => _data[3] = FromFloat(value);
}
public float GlossStrength
{
get => ToFloat(7);
set => _data[7] = FromFloat(value);
}
public ushort TileSet
{
get => (ushort)(ToFloat(11) * 64f);
set => _data[11] = FromFloat(value / 64f);
}
private float ToFloat(int idx)
=> (float)BitConverter.UInt16BitsToHalf(_data[idx]);
private static ushort FromFloat(float x)
=> BitConverter.HalfToUInt16Bits((Half)x);
}
public struct RowArray : IEnumerable<Row>
{
public const int NumRows = 16;
private fixed byte _rowData[NumRows * Row.Size];
public ref Row this[int i]
{
get
{
fixed (byte* ptr = _rowData)
{
return ref ((Row*)ptr)[i];
}
}
}
public IEnumerator<Row> GetEnumerator()
{
for (var i = 0; i < NumRows; ++i)
yield return this[i];
}
IEnumerator IEnumerable.GetEnumerator()
=> GetEnumerator();
public ReadOnlySpan<byte> AsBytes()
{
fixed (byte* ptr = _rowData)
{
return new ReadOnlySpan<byte>(ptr, NumRows * Row.Size);
}
}
}
public RowArray Rows;
public string Name;
public ushort Index;
public bool HasRows;
}
public unsafe struct ColorDyeSet
{
public struct Row
{
private ushort _data;
public ushort Template
{
get => (ushort)(_data >> 5);
set => _data = (ushort)((_data & 0x1F) | (value << 5));
}
public bool Diffuse
{
get => (_data & 0x01) != 0;
set => _data = (ushort)(value ? _data | 0x01 : _data & 0xFFFE);
}
public bool Specular
{
get => (_data & 0x02) != 0;
set => _data = (ushort)(value ? _data | 0x02 : _data & 0xFFFD);
}
public bool Emissive
{
get => (_data & 0x04) != 0;
set => _data = (ushort)(value ? _data | 0x04 : _data & 0xFFFB);
}
public bool Gloss
{
get => (_data & 0x08) != 0;
set => _data = (ushort)(value ? _data | 0x08 : _data & 0xFFF7);
}
public bool SpecularStrength
{
get => (_data & 0x10) != 0;
set => _data = (ushort)(value ? _data | 0x10 : _data & 0xFFEF);
}
}
public struct RowArray : IEnumerable<Row>
{
public const int NumRows = 16;
private fixed ushort _rowData[NumRows];
public ref Row this[int i]
{
get
{
fixed (ushort* ptr = _rowData)
{
return ref ((Row*)ptr)[i];
}
}
}
public IEnumerator<Row> GetEnumerator()
{
for (var i = 0; i < NumRows; ++i)
yield return this[i];
}
IEnumerator IEnumerable.GetEnumerator()
=> GetEnumerator();
public ReadOnlySpan<byte> AsBytes()
{
fixed (ushort* ptr = _rowData)
{
return new ReadOnlySpan<byte>(ptr, NumRows * sizeof(ushort));
}
}
}
public RowArray Rows;
public string Name;
public ushort Index;
}
public struct Texture
{
public string Path;
public ushort Flags;
public bool DX11
=> (Flags & 0x8000) != 0;
}
public struct Constant
{
public uint Id;
public ushort ByteOffset;
public ushort ByteSize;
}
public struct ShaderPackageData
{
public string Name;
public ShaderKey[] ShaderKeys;
public Constant[] Constants;
public Sampler[] Samplers;
public float[] ShaderValues;
public uint Flags;
}
public readonly uint Version;
public bool Valid
{
get
{
foreach (var texture in Textures)
{
if (!texture.Path.Contains('/'))
{
return false;
}
}
return true;
}
}
public bool Valid
=> CheckTextures();
public Texture[] Textures;
public UvSet[] UvSets;
@ -277,7 +23,7 @@ public partial class MtrlFile : IWritable
public ShaderPackageData ShaderPackage;
public byte[] AdditionalData;
public ShpkFile? AssociatedShpk;
public ShpkFile? AssociatedShpk;
public bool ApplyDyeTemplate(StmFile stm, int colorSetIdx, int rowIdx, StainId stainId)
{
@ -324,15 +70,13 @@ public partial class MtrlFile : IWritable
public Span<float> GetConstantValues(Constant constant)
{
if ((constant.ByteOffset & 0x3) == 0 && (constant.ByteSize & 0x3) == 0
&& ((constant.ByteOffset + constant.ByteSize) >> 2) <= ShaderPackage.ShaderValues.Length)
{
return ShaderPackage.ShaderValues.AsSpan().Slice(constant.ByteOffset >> 2, constant.ByteSize >> 2);
}
else
{
if ((constant.ByteOffset & 0x3) != 0
|| (constant.ByteSize & 0x3) != 0
|| (constant.ByteOffset + constant.ByteSize) >> 2 > ShaderPackage.ShaderValues.Length)
return null;
}
return ShaderPackage.ShaderValues.AsSpan().Slice(constant.ByteOffset >> 2, constant.ByteSize >> 2);
}
public List<(Sampler?, ShpkFile.Resource?)> GetSamplersByTexture()
@ -348,13 +92,7 @@ public partial class MtrlFile : IWritable
}
return samplers;
}
// Activator.CreateInstance can't use a ctor with a default value so this has to be made explicit
public MtrlFile(byte[] data)
: this(data, null)
{
}
}
public MtrlFile(byte[] data, Func<string, ShpkFile?>? loadAssociatedShpk = null)
{
@ -469,6 +207,41 @@ public partial class MtrlFile : IWritable
{
strings = strings[offset..];
var end = strings.IndexOf((byte)'\0');
return Encoding.UTF8.GetString(strings[..end]);
return Encoding.UTF8.GetString(end == -1 ? strings : strings[..end]);
}
private bool CheckTextures()
=> Textures.All(texture => texture.Path.Contains('/'));
public struct UvSet
{
public string Name;
public ushort Index;
}
public struct Texture
{
public string Path;
public ushort Flags;
public bool DX11
=> (Flags & 0x8000) != 0;
}
public struct Constant
{
public uint Id;
public ushort ByteOffset;
public ushort ByteSize;
}
public struct ShaderPackageData
{
public string Name;
public ShaderKey[] ShaderKeys;
public Constant[] Constants;
public Sampler[] Samplers;
public float[] ShaderValues;
public uint Flags;
}
}

View file

@ -0,0 +1,220 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Lumina.Misc;
using Penumbra.GameData.Data;
namespace Penumbra.GameData.Files;
public partial class ShpkFile
{
public struct Shader
{
public DisassembledShader.ShaderStage Stage;
public DxVersion DirectXVersion;
public Resource[] Constants;
public Resource[] Samplers;
public Resource[] Uavs;
public byte[] AdditionalHeader;
private byte[] _byteData;
private DisassembledShader? _disassembly;
public byte[] Blob
{
get => _byteData;
set
{
if (_byteData == value)
return;
if (Stage != DisassembledShader.ShaderStage.Unspecified)
{
// Reject the blob entirely if we can't disassemble it or if we find inconsistencies.
var disasm = DisassembledShader.Disassemble(value);
if (disasm.Stage != Stage || (disasm.ShaderModel >> 8) + 6 != (uint)DirectXVersion)
throw new ArgumentException(
$"The supplied blob is a DirectX {(disasm.ShaderModel >> 8) + 6} {disasm.Stage} shader ; expected a DirectX {(uint)DirectXVersion} {Stage} shader.",
nameof(value));
if (disasm.ShaderModel >= 0x0500)
{
var samplers = new Dictionary<uint, string>();
var textures = new Dictionary<uint, string>();
foreach (var binding in disasm.ResourceBindings)
{
switch (binding.Type)
{
case DisassembledShader.ResourceType.Texture:
textures[binding.Slot] = NormalizeResourceName(binding.Name);
break;
case DisassembledShader.ResourceType.Sampler:
samplers[binding.Slot] = NormalizeResourceName(binding.Name);
break;
}
}
if (samplers.Count != textures.Count
|| !samplers.All(pair => textures.TryGetValue(pair.Key, out var texName) && pair.Value == texName))
throw new ArgumentException($"The supplied blob has inconsistent sampler and texture allocation.");
}
_byteData = value;
_disassembly = disasm;
}
else
{
_byteData = value;
_disassembly = null;
}
UpdateUsed();
}
}
public DisassembledShader? Disassembly
=> _disassembly;
public Resource? GetConstantById(uint id)
=> Constants.FirstOrNull(res => res.Id == id);
public Resource? GetConstantByName(string name)
=> Constants.FirstOrNull(res => res.Name == name);
public Resource? GetSamplerById(uint id)
=> Samplers.FirstOrNull(s => s.Id == id);
public Resource? GetSamplerByName(string name)
=> Samplers.FirstOrNull(s => s.Name == name);
public Resource? GetUavById(uint id)
=> Uavs.FirstOrNull(u => u.Id == id);
public Resource? GetUavByName(string name)
=> Uavs.FirstOrNull(u => u.Name == name);
public void UpdateResources(ShpkFile file)
{
if (_disassembly == null)
throw new InvalidOperationException();
var constants = new List<Resource>();
var samplers = new List<Resource>();
var uavs = new List<Resource>();
foreach (var binding in _disassembly.ResourceBindings)
{
switch (binding.Type)
{
case DisassembledShader.ResourceType.ConstantBuffer:
var name = NormalizeResourceName(binding.Name);
// We want to preserve IDs as much as possible, and to deterministically generate new ones in a way that's most compliant with the native ones, to maximize compatibility.
var id = GetConstantByName(name)?.Id ?? file.GetConstantByName(name)?.Id ?? Crc32.Get(name, 0xFFFFFFFFu);
constants.Add(new Resource
{
Id = id,
Name = name,
Slot = (ushort)binding.Slot,
Size = (ushort)binding.RegisterCount,
Used = binding.Used,
UsedDynamically = binding.UsedDynamically,
});
break;
case DisassembledShader.ResourceType.Texture:
name = NormalizeResourceName(binding.Name);
id = GetSamplerByName(name)?.Id ?? file.GetSamplerByName(name)?.Id ?? Crc32.Get(name, 0xFFFFFFFFu);
samplers.Add(new Resource
{
Id = id,
Name = name,
Slot = (ushort)binding.Slot,
Size = (ushort)binding.Slot,
Used = binding.Used,
UsedDynamically = binding.UsedDynamically,
});
break;
case DisassembledShader.ResourceType.Uav:
name = NormalizeResourceName(binding.Name);
id = GetUavByName(name)?.Id ?? file.GetUavByName(name)?.Id ?? Crc32.Get(name, 0xFFFFFFFFu);
uavs.Add(new Resource
{
Id = id,
Name = name,
Slot = (ushort)binding.Slot,
Size = (ushort)binding.Slot,
Used = binding.Used,
UsedDynamically = binding.UsedDynamically,
});
break;
}
}
Constants = constants.ToArray();
Samplers = samplers.ToArray();
Uavs = uavs.ToArray();
}
private void UpdateUsed()
{
if (_disassembly != null)
{
var cbUsage = new Dictionary<string, (DisassembledShader.VectorComponents[], DisassembledShader.VectorComponents)>();
var tUsage = new Dictionary<string, (DisassembledShader.VectorComponents[], DisassembledShader.VectorComponents)>();
var uUsage = new Dictionary<string, (DisassembledShader.VectorComponents[], DisassembledShader.VectorComponents)>();
foreach (var binding in _disassembly.ResourceBindings)
{
switch (binding.Type)
{
case DisassembledShader.ResourceType.ConstantBuffer:
cbUsage[NormalizeResourceName(binding.Name)] = (binding.Used, binding.UsedDynamically);
break;
case DisassembledShader.ResourceType.Texture:
tUsage[NormalizeResourceName(binding.Name)] = (binding.Used, binding.UsedDynamically);
break;
case DisassembledShader.ResourceType.Uav:
uUsage[NormalizeResourceName(binding.Name)] = (binding.Used, binding.UsedDynamically);
break;
}
}
static void CopyUsed(Resource[] resources,
Dictionary<string, (DisassembledShader.VectorComponents[], DisassembledShader.VectorComponents)> used)
{
for (var i = 0; i < resources.Length; ++i)
{
if (used.TryGetValue(resources[i].Name, out var usage))
{
resources[i].Used = usage.Item1;
resources[i].UsedDynamically = usage.Item2;
}
else
{
resources[i].Used = null;
resources[i].UsedDynamically = null;
}
}
}
CopyUsed(Constants, cbUsage);
CopyUsed(Samplers, tUsage);
CopyUsed(Uavs, uUsage);
}
else
{
ClearUsed(Constants);
ClearUsed(Samplers);
ClearUsed(Uavs);
}
}
private static string NormalizeResourceName(string resourceName)
{
var dot = resourceName.IndexOf('.');
if (dot >= 0)
return resourceName[..dot];
if (resourceName.Length > 1 && resourceName[^2] is '_' && resourceName[^1] is 'S' or 'T')
return resourceName[..^2];
return resourceName;
}
}
}

View file

@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Penumbra.GameData.Files;
public partial class ShpkFile
{
public class StringPool
{
public MemoryStream Data;
public List<int> StartingOffsets;
public StringPool(ReadOnlySpan<byte> bytes)
{
Data = new MemoryStream();
Data.Write(bytes);
StartingOffsets = new List<int>
{
0,
};
for (var i = 0; i < bytes.Length; ++i)
{
if (bytes[i] == 0)
StartingOffsets.Add(i + 1);
}
if (StartingOffsets[^1] == bytes.Length)
StartingOffsets.RemoveAt(StartingOffsets.Count - 1);
else
Data.WriteByte(0);
}
public string GetString(int offset, int size)
=> Encoding.UTF8.GetString(Data.GetBuffer().AsSpan().Slice(offset, size));
public string GetNullTerminatedString(int offset)
{
var str = Data.GetBuffer().AsSpan()[offset..];
var size = str.IndexOf((byte)0);
if (size >= 0)
str = str[..size];
return Encoding.UTF8.GetString(str);
}
public (int, int) FindOrAddString(string str)
{
var dataSpan = Data.GetBuffer().AsSpan();
var bytes = Encoding.UTF8.GetBytes(str);
foreach (var offset in StartingOffsets)
{
if (offset + bytes.Length > Data.Length)
break;
var strSpan = dataSpan[offset..];
var match = true;
for (var i = 0; i < bytes.Length; ++i)
{
if (strSpan[i] != bytes[i])
{
match = false;
break;
}
}
if (match && strSpan[bytes.Length] == 0)
return (offset, bytes.Length);
}
Data.Seek(0L, SeekOrigin.End);
var newOffset = (int)Data.Position;
StartingOffsets.Add(newOffset);
Data.Write(bytes);
Data.WriteByte(0);
return (newOffset, bytes.Length);
}
}
}

View file

@ -8,21 +8,19 @@ public partial class ShpkFile
public byte[] Write()
{
if (SubViewKeys.Length != 2)
{
throw new InvalidDataException();
}
using var stream = new MemoryStream();
using var blobs = new MemoryStream();
var strings = new StringPool(ReadOnlySpan<byte>.Empty);
using var stream = new MemoryStream();
using var blobs = new MemoryStream();
var strings = new StringPool(ReadOnlySpan<byte>.Empty);
using (var w = new BinaryWriter(stream))
{
w.Write(ShPkMagic);
w.Write(Version);
w.Write(DirectXVersion switch
{
DXVersion.DirectX9 => DX9Magic,
DXVersion.DirectX11 => DX11Magic,
DxVersion.DirectX9 => Dx9Magic,
DxVersion.DirectX11 => Dx11Magic,
_ => throw new NotImplementedException(),
});
var offsetsPosition = stream.Position;
@ -35,7 +33,7 @@ public partial class ShpkFile
w.Write((uint)MaterialParams.Length);
w.Write((uint)Constants.Length);
w.Write((uint)Samplers.Length);
w.Write((uint)UAVs.Length);
w.Write((uint)Uavs.Length);
w.Write((uint)SystemKeys.Length);
w.Write((uint)SceneKeys.Length);
w.Write((uint)MaterialKeys.Length);
@ -43,7 +41,7 @@ public partial class ShpkFile
w.Write((uint)Items.Length);
WriteShaderArray(w, VertexShaders, blobs, strings);
WriteShaderArray(w, PixelShaders, blobs, strings);
WriteShaderArray(w, PixelShaders, blobs, strings);
foreach (var materialParam in MaterialParams)
{
@ -53,54 +51,50 @@ public partial class ShpkFile
}
WriteResourceArray(w, Constants, strings);
WriteResourceArray(w, Samplers, strings);
WriteResourceArray(w, UAVs, strings);
WriteResourceArray(w, Samplers, strings);
WriteResourceArray(w, Uavs, strings);
foreach (var key in SystemKeys)
{
w.Write(key.Id);
w.Write(key.DefaultValue);
}
foreach (var key in SceneKeys)
{
w.Write(key.Id);
w.Write(key.DefaultValue);
}
foreach (var key in MaterialKeys)
{
w.Write(key.Id);
w.Write(key.DefaultValue);
}
foreach (var key in SubViewKeys)
{
w.Write(key.DefaultValue);
}
foreach (var node in Nodes)
{
if (node.PassIndices.Length != 16 || node.SystemKeys.Length != SystemKeys.Length || node.SceneKeys.Length != SceneKeys.Length || node.MaterialKeys.Length != MaterialKeys.Length || node.SubViewKeys.Length != SubViewKeys.Length)
{
if (node.PassIndices.Length != 16
|| node.SystemKeys.Length != SystemKeys.Length
|| node.SceneKeys.Length != SceneKeys.Length
|| node.MaterialKeys.Length != MaterialKeys.Length
|| node.SubViewKeys.Length != SubViewKeys.Length)
throw new InvalidDataException();
}
w.Write(node.Id);
w.Write(node.Passes.Length);
w.Write(node.PassIndices);
foreach (var key in node.SystemKeys)
{
w.Write(key);
}
foreach (var key in node.SceneKeys)
{
w.Write(key);
}
foreach (var key in node.MaterialKeys)
{
w.Write(key);
}
foreach (var key in node.SubViewKeys)
{
w.Write(key);
}
foreach (var pass in node.Passes)
{
w.Write(pass.Id);
@ -160,21 +154,12 @@ public partial class ShpkFile
w.Write(blobSize);
w.Write((ushort)shader.Constants.Length);
w.Write((ushort)shader.Samplers.Length);
w.Write((ushort)shader.UAVs.Length);
w.Write((ushort)shader.Uavs.Length);
w.Write((ushort)0);
WriteResourceArray(w, shader.Constants, strings);
WriteResourceArray(w, shader.Samplers, strings);
WriteResourceArray(w, shader.UAVs, strings);
}
}
private static void WriteUInt32PairArray(BinaryWriter w, (uint, uint)[] array)
{
foreach (var (first, second) in array)
{
w.Write(first);
w.Write(second);
WriteResourceArray(w, shader.Samplers, strings);
WriteResourceArray(w, shader.Uavs, strings);
}
}
}

File diff suppressed because it is too large Load diff