diff --git a/Glamourer/Gui/Materials/AdvancedDyePopup.cs b/Glamourer/Gui/Materials/AdvancedDyePopup.cs index a9ab805..3ba2a1b 100644 --- a/Glamourer/Gui/Materials/AdvancedDyePopup.cs +++ b/Glamourer/Gui/Materials/AdvancedDyePopup.cs @@ -102,10 +102,12 @@ public sealed unsafe class AdvancedDyePopup( if (!bar) return; + var table = new ColorTable.Table(); for (byte i = 0; i < MaterialService.MaterialsPerModel; ++i) { var index = _drawIndex!.Value with { MaterialIndex = i }; - var available = index.TryGetTexture(textures, out var texture) && directX.TryGetColorTable(*texture, out var table); + var available = index.TryGetTexture(textures, out var texture) && directX.TryGetColorTable(*texture, out table); + if (index == preview.LastValueIndex with { RowIndex = 0 }) table = preview.LastOriginalColorTable; @@ -225,7 +227,7 @@ public sealed unsafe class AdvancedDyePopup( DrawWindow(textures); } - private void DrawTable(MaterialValueIndex materialIndex, in ColorTable table) + private void DrawTable(MaterialValueIndex materialIndex, ColorTable.Table table) { if (!materialIndex.Valid) return; @@ -244,7 +246,7 @@ public sealed unsafe class AdvancedDyePopup( DrawAllRow(materialIndex, table); } - private void DrawAllRow(MaterialValueIndex materialIndex, in ColorTable table) + private void DrawAllRow(MaterialValueIndex materialIndex, in ColorTable.Table table) { using var id = ImRaii.PushId(100); var buttonSize = new Vector2(ImGui.GetFrameHeight()); @@ -267,8 +269,9 @@ public sealed unsafe class AdvancedDyePopup( ImGui.SameLine(0, spacing); if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Paste.ToIconString(), buttonSize, "Import an exported table from your clipboard onto this table.", !ColorRowClipboard.IsTableSet, true)) - foreach (var (row, idx) in ColorRowClipboard.Table.WithIndex()) + for (var idx = 0; idx < ColorTable.NumRows; ++idx) { + var row = ColorRowClipboard.Table[idx]; var internalRow = new ColorRow(row); var slot = materialIndex.ToEquipSlot(); var weapon = slot is EquipSlot.MainHand or EquipSlot.OffHand @@ -285,7 +288,7 @@ public sealed unsafe class AdvancedDyePopup( stateManager.ResetMaterialValue(_state, materialIndex with { RowIndex = i }, ApplySettings.Game); } - private void DrawRow(ref ColorTable.Row row, MaterialValueIndex index, in ColorTable table) + private void DrawRow(ref ColorTableRow row, MaterialValueIndex index, in ColorTable.Table table) { using var id = ImRaii.PushId(index.RowIndex); var changed = _state.Materials.TryGetValue(index, out var value); diff --git a/Glamourer/Gui/Materials/ColorRowClipboard.cs b/Glamourer/Gui/Materials/ColorRowClipboard.cs index 4213cc5..f7fac1d 100644 --- a/Glamourer/Gui/Materials/ColorRowClipboard.cs +++ b/Glamourer/Gui/Materials/ColorRowClipboard.cs @@ -6,13 +6,13 @@ namespace Glamourer.Gui.Materials; public static class ColorRowClipboard { private static ColorRow _row; - private static ColorTable _table; + private static ColorTable.Table _table; public static bool IsSet { get; private set; } public static bool IsTableSet { get; private set; } - public static ColorTable Table + public static ColorTable.Table Table { get => _table; set diff --git a/Glamourer/Interop/Material/DirectXService.cs b/Glamourer/Interop/Material/DirectXService.cs index 3316491..a809a34 100644 --- a/Glamourer/Interop/Material/DirectXService.cs +++ b/Glamourer/Interop/Material/DirectXService.cs @@ -15,13 +15,13 @@ namespace Glamourer.Interop.Material; public unsafe class DirectXService(IFramework framework) : IService { private readonly object _lock = new(); - private readonly ConcurrentDictionary _textures = []; + private readonly ConcurrentDictionary _textures = []; /// Generate a color table the way the game does inside the original texture, and release the original. /// The original texture that will be replaced with a new one. /// The input color table. /// Success or failure. - public bool ReplaceColorTable(Texture** original, in ColorTable colorTable) + public bool ReplaceColorTable(Texture** original, in ColorTable.Table colorTable) { if (original == null) return false; @@ -38,7 +38,7 @@ public unsafe class DirectXService(IFramework framework) : IService if (texture.IsInvalid) return false; - fixed (ColorTable* ptr = &colorTable) + fixed (ColorTable.Table* ptr = &colorTable) { if (!texture.Texture->InitializeContents(ptr)) return false; @@ -51,7 +51,7 @@ public unsafe class DirectXService(IFramework framework) : IService return true; } - public bool TryGetColorTable(Texture* texture, out ColorTable table) + public bool TryGetColorTable(Texture* texture, out ColorTable.Table table) { if (_textures.TryGetValue((nint)texture, out var p) && framework.LastUpdateUTC == p.Update) { @@ -73,7 +73,7 @@ public unsafe class DirectXService(IFramework framework) : IService /// A pointer to the internal texture struct containing the GPU handle. /// The returned color table. /// Whether the table could be fetched. - private static bool TextureColorTable(Texture* texture, out ColorTable table) + private static bool TextureColorTable(Texture* texture, out ColorTable.Table table) { if (texture == null) { @@ -92,6 +92,7 @@ public unsafe class DirectXService(IFramework framework) : IService } catch { + table = default; return false; } } @@ -114,7 +115,7 @@ public unsafe class DirectXService(IFramework framework) : IService } /// Turn a mapped texture into a color table. - private static ColorTable GetTextureData(ID3D11Texture2D1 resource, MappedSubresource map) + private static ColorTable.Table GetTextureData(ID3D11Texture2D1 resource, MappedSubresource map) { var desc = resource.Description1; @@ -133,14 +134,14 @@ public unsafe class DirectXService(IFramework framework) : IService /// The height of the texture. (Needs to be 16). /// The stride in the texture data. /// - private static ColorTable ReadTexture(nint data, int length, int height, int pitch) + private static ColorTable.Table ReadTexture(nint data, int length, int height, int pitch) { // Check that the data has sufficient dimension and size. var expectedSize = sizeof(Half) * MaterialService.TextureWidth * height * 4; - if (length < expectedSize || sizeof(ColorTable) != expectedSize || height != MaterialService.TextureHeight) + if (length < expectedSize || sizeof(ColorTable.Table) != expectedSize || height != MaterialService.TextureHeight) return default; - var ret = new ColorTable(); + var ret = new ColorTable.Table(); var target = (byte*)&ret; // If the stride is the same as in the table, just copy. if (pitch == MaterialService.TextureWidth) diff --git a/Glamourer/Interop/Material/LiveColorTablePreviewer.cs b/Glamourer/Interop/Material/LiveColorTablePreviewer.cs index 1df85f6..94cb9ca 100644 --- a/Glamourer/Interop/Material/LiveColorTablePreviewer.cs +++ b/Glamourer/Interop/Material/LiveColorTablePreviewer.cs @@ -13,11 +13,11 @@ public sealed unsafe class LiveColorTablePreviewer : IService, IDisposable private readonly DirectXService _directXService; public MaterialValueIndex LastValueIndex { get; private set; } = MaterialValueIndex.Invalid; - public ColorTable LastOriginalColorTable { get; private set; } + public ColorTable.Table LastOriginalColorTable { get; private set; } private MaterialValueIndex _valueIndex = MaterialValueIndex.Invalid; private ObjectIndex _lastObjectIndex = ObjectIndex.AnyIndex; private ObjectIndex _objectIndex = ObjectIndex.AnyIndex; - private ColorTable _originalColorTable; + private ColorTable.Table _originalColorTable; public LiveColorTablePreviewer(global::Penumbra.GameData.Interop.ObjectManager objects, IFramework framework, DirectXService directXService) { @@ -73,15 +73,15 @@ public sealed unsafe class LiveColorTablePreviewer : IService, IDisposable var table = LastOriginalColorTable; if (_valueIndex.RowIndex != byte.MaxValue) { - table[_valueIndex.RowIndex].Diffuse = diffuse; - table[_valueIndex.RowIndex].Emissive = emissive; + table[_valueIndex.RowIndex].DiffuseColor = (HalfColor)diffuse; + table[_valueIndex.RowIndex].EmissiveColor = (HalfColor)emissive; } else { for (var i = 0; i < ColorTable.NumRows; ++i) { - table[i].Diffuse = diffuse; - table[i].Emissive = emissive; + table[i].DiffuseColor = (HalfColor)diffuse; + table[i].EmissiveColor = (HalfColor)emissive; } } @@ -92,7 +92,7 @@ public sealed unsafe class LiveColorTablePreviewer : IService, IDisposable _objectIndex = ObjectIndex.AnyIndex; } - public void OnHover(MaterialValueIndex index, ObjectIndex objectIndex, ColorTable table) + public void OnHover(MaterialValueIndex index, ObjectIndex objectIndex, in ColorTable.Table table) { if (_valueIndex.DrawObject is not MaterialValueIndex.DrawObjectType.Invalid) return; diff --git a/Glamourer/Interop/Material/MaterialManager.cs b/Glamourer/Interop/Material/MaterialManager.cs index e695a90..3e0e35b 100644 --- a/Glamourer/Interop/Material/MaterialManager.cs +++ b/Glamourer/Interop/Material/MaterialManager.cs @@ -75,7 +75,7 @@ public sealed unsafe class MaterialManager : IRequiredService, IDisposable /// Update and apply the glamourer state of an actor according to the application sources when updated by the game. private void UpdateMaterialValues(ActorState state, ReadOnlySpan<(uint Key, MaterialValueState Value)> values, CharacterWeapon drawData, - ref ColorTable colorTable) + ref ColorTable.Table colorTable) { var deleteList = _deleteList.Value!; deleteList.Clear(); diff --git a/Glamourer/Interop/Material/MaterialService.cs b/Glamourer/Interop/Material/MaterialService.cs index 5adaf4d..f7ffe0f 100644 --- a/Glamourer/Interop/Material/MaterialService.cs +++ b/Glamourer/Interop/Material/MaterialService.cs @@ -13,7 +13,7 @@ public static unsafe class MaterialService public const int TextureHeight = ColorTable.NumRows; public const int MaterialsPerModel = 10; - public static bool GenerateNewColorTable(in ColorTable colorTable, out Texture* texture) + public static bool GenerateNewColorTable(in ColorTable.Table colorTable, out Texture* texture) { var textureSize = stackalloc int[2]; textureSize[0] = TextureWidth; @@ -24,7 +24,7 @@ public static unsafe class MaterialService if (texture == null) return false; - fixed (ColorTable* ptr = &colorTable) + fixed (ColorTable.Table* ptr = &colorTable) { return texture->InitializeContents(ptr); } @@ -53,7 +53,7 @@ public static unsafe class MaterialService /// The model slot. /// The material slot in the model. /// A pointer to the color table or null. - public static ColorTable* GetMaterialColorTable(Model model, int modelSlot, byte materialSlot) + public static ColorTable.Table* GetMaterialColorTable(Model model, int modelSlot, byte materialSlot) { if (!model.IsCharacterBase) return null; @@ -66,6 +66,6 @@ public static unsafe class MaterialService if (material == null || material->ColorTable == null) return null; - return (ColorTable*)material->ColorTable; + return (ColorTable.Table*)material->ColorTable; } } diff --git a/Glamourer/Interop/Material/MaterialValueManager.cs b/Glamourer/Interop/Material/MaterialValueManager.cs index d5ac877..79338a0 100644 --- a/Glamourer/Interop/Material/MaterialValueManager.cs +++ b/Glamourer/Interop/Material/MaterialValueManager.cs @@ -21,8 +21,9 @@ public struct ColorRow(Vector3 diffuse, Vector3 specular, Vector3 emissive, floa public float SpecularStrength = specularStrength; public float GlossStrength = glossStrength; - public ColorRow(in ColorTable.Row row) - : this(Root(row.Diffuse), Root(row.Specular), Root(row.Emissive), row.SpecularStrength, row.GlossStrength) + public ColorRow(in ColorTableRow row) + : this(Root((Vector3)row.DiffuseColor), Root((Vector3)row.SpecularColor), Root((Vector3)row.EmissiveColor), (float)row.SheenRate, + (float)row.Metalness) { } public readonly bool NearEqual(in ColorRow rhs) @@ -44,39 +45,39 @@ public struct ColorRow(Vector3 diffuse, Vector3 specular, Vector3 emissive, floa private static float Root(float value) => value < 0 ? MathF.Sqrt(-value) : MathF.Sqrt(value); - public readonly bool Apply(ref ColorTable.Row row) + public readonly bool Apply(ref ColorTableRow row) { var ret = false; var d = Square(Diffuse); - if (!row.Diffuse.NearEqual(d)) + if (!((Vector3)row.DiffuseColor).NearEqual(d)) { - row.Diffuse = d; - ret = true; + row.DiffuseColor = (HalfColor)d; + ret = true; } var s = Square(Specular); - if (!row.Specular.NearEqual(s)) + if (!((Vector3)row.SpecularColor).NearEqual(s)) { - row.Specular = s; - ret = true; + row.SpecularColor = (HalfColor)s; + ret = true; } var e = Square(Emissive); - if (!row.Emissive.NearEqual(e)) + if (!((Vector3)row.EmissiveColor).NearEqual(e)) { - row.Emissive = e; - ret = true; + row.EmissiveColor = (HalfColor)e; + ret = true; } - if (!row.SpecularStrength.NearEqual(SpecularStrength)) + if (!((float)row.SheenRate).NearEqual(SpecularStrength)) { - row.SpecularStrength = SpecularStrength; - ret = true; + row.SheenRate = (Half)SpecularStrength; + ret = true; } - if (!row.GlossStrength.NearEqual(GlossStrength)) + if (!((float)row.Metalness).NearEqual(GlossStrength)) { - row.GlossStrength = GlossStrength; + row.Metalness = (Half)GlossStrength; ret = true; } diff --git a/Glamourer/Interop/Material/PrepareColorSet.cs b/Glamourer/Interop/Material/PrepareColorSet.cs index b8e31c2..6d65a6b 100644 --- a/Glamourer/Interop/Material/PrepareColorSet.cs +++ b/Glamourer/Interop/Material/PrepareColorSet.cs @@ -66,7 +66,7 @@ public sealed unsafe class PrepareColorSet } public static bool TryGetColorTable(MaterialResourceHandle* material, StainIds stainIds, - out ColorTable table) + out ColorTable.Table table) { if (material->ColorTable == null) { @@ -74,7 +74,7 @@ public sealed unsafe class PrepareColorSet return false; } - var newTable = *(ColorTable*)material->ColorTable; + var newTable = *(ColorTable.Table*)material->ColorTable; if (GetDyeTable(material, out var dyeTable)) { if (stainIds.Stain1.Id != 0) @@ -91,11 +91,14 @@ public sealed unsafe class PrepareColorSet } /// Assumes the actor is valid. - public static bool TryGetColorTable(Actor actor, MaterialValueIndex index, out ColorTable table) + public static bool TryGetColorTable(Actor actor, MaterialValueIndex index, out ColorTable.Table table) { var idx = index.SlotIndex * MaterialService.MaterialsPerModel + index.MaterialIndex; if (!index.TryGetModel(actor, out var model)) + { + table = default; return false; + } var handle = (MaterialResourceHandle*)model.AsCharacterBase->Materials[idx]; if (handle == null) diff --git a/Penumbra.GameData b/Penumbra.GameData index ad6973c..016da3c 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit ad6973c559b4c05aa3c3735ec7b53cc0f5d2f203 +Subproject commit 016da3c2219a3dbe4c2841ae0d1305ae0b2ad60f