Update for GameData update.

This commit is contained in:
Ottermandias 2024-08-06 18:25:00 +02:00
parent 2e52030c31
commit 61cb46a298
9 changed files with 57 additions and 49 deletions

View file

@ -102,10 +102,12 @@ public sealed unsafe class AdvancedDyePopup(
if (!bar) if (!bar)
return; return;
var table = new ColorTable.Table();
for (byte i = 0; i < MaterialService.MaterialsPerModel; ++i) for (byte i = 0; i < MaterialService.MaterialsPerModel; ++i)
{ {
var index = _drawIndex!.Value with { MaterialIndex = 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 }) if (index == preview.LastValueIndex with { RowIndex = 0 })
table = preview.LastOriginalColorTable; table = preview.LastOriginalColorTable;
@ -225,7 +227,7 @@ public sealed unsafe class AdvancedDyePopup(
DrawWindow(textures); DrawWindow(textures);
} }
private void DrawTable(MaterialValueIndex materialIndex, in ColorTable table) private void DrawTable(MaterialValueIndex materialIndex, ColorTable.Table table)
{ {
if (!materialIndex.Valid) if (!materialIndex.Valid)
return; return;
@ -244,7 +246,7 @@ public sealed unsafe class AdvancedDyePopup(
DrawAllRow(materialIndex, table); 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); using var id = ImRaii.PushId(100);
var buttonSize = new Vector2(ImGui.GetFrameHeight()); var buttonSize = new Vector2(ImGui.GetFrameHeight());
@ -267,8 +269,9 @@ public sealed unsafe class AdvancedDyePopup(
ImGui.SameLine(0, spacing); ImGui.SameLine(0, spacing);
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Paste.ToIconString(), buttonSize, if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Paste.ToIconString(), buttonSize,
"Import an exported table from your clipboard onto this table.", !ColorRowClipboard.IsTableSet, true)) "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 internalRow = new ColorRow(row);
var slot = materialIndex.ToEquipSlot(); var slot = materialIndex.ToEquipSlot();
var weapon = slot is EquipSlot.MainHand or EquipSlot.OffHand 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); 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); using var id = ImRaii.PushId(index.RowIndex);
var changed = _state.Materials.TryGetValue(index, out var value); var changed = _state.Materials.TryGetValue(index, out var value);

View file

@ -6,13 +6,13 @@ namespace Glamourer.Gui.Materials;
public static class ColorRowClipboard public static class ColorRowClipboard
{ {
private static ColorRow _row; private static ColorRow _row;
private static ColorTable _table; private static ColorTable.Table _table;
public static bool IsSet { get; private set; } public static bool IsSet { get; private set; }
public static bool IsTableSet { get; private set; } public static bool IsTableSet { get; private set; }
public static ColorTable Table public static ColorTable.Table Table
{ {
get => _table; get => _table;
set set

View file

@ -15,13 +15,13 @@ namespace Glamourer.Interop.Material;
public unsafe class DirectXService(IFramework framework) : IService public unsafe class DirectXService(IFramework framework) : IService
{ {
private readonly object _lock = new(); private readonly object _lock = new();
private readonly ConcurrentDictionary<nint, (DateTime Update, ColorTable Table)> _textures = []; private readonly ConcurrentDictionary<nint, (DateTime Update, ColorTable.Table Table)> _textures = [];
/// <summary> Generate a color table the way the game does inside the original texture, and release the original. </summary> /// <summary> Generate a color table the way the game does inside the original texture, and release the original. </summary>
/// <param name="original"> The original texture that will be replaced with a new one. </param> /// <param name="original"> The original texture that will be replaced with a new one. </param>
/// <param name="colorTable"> The input color table. </param> /// <param name="colorTable"> The input color table. </param>
/// <returns> Success or failure. </returns> /// <returns> Success or failure. </returns>
public bool ReplaceColorTable(Texture** original, in ColorTable colorTable) public bool ReplaceColorTable(Texture** original, in ColorTable.Table colorTable)
{ {
if (original == null) if (original == null)
return false; return false;
@ -38,7 +38,7 @@ public unsafe class DirectXService(IFramework framework) : IService
if (texture.IsInvalid) if (texture.IsInvalid)
return false; return false;
fixed (ColorTable* ptr = &colorTable) fixed (ColorTable.Table* ptr = &colorTable)
{ {
if (!texture.Texture->InitializeContents(ptr)) if (!texture.Texture->InitializeContents(ptr))
return false; return false;
@ -51,7 +51,7 @@ public unsafe class DirectXService(IFramework framework) : IService
return true; 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) if (_textures.TryGetValue((nint)texture, out var p) && framework.LastUpdateUTC == p.Update)
{ {
@ -73,7 +73,7 @@ public unsafe class DirectXService(IFramework framework) : IService
/// <param name="texture"> A pointer to the internal texture struct containing the GPU handle. </param> /// <param name="texture"> A pointer to the internal texture struct containing the GPU handle. </param>
/// <param name="table"> The returned color table. </param> /// <param name="table"> The returned color table. </param>
/// <returns> Whether the table could be fetched. </returns> /// <returns> Whether the table could be fetched. </returns>
private static bool TextureColorTable(Texture* texture, out ColorTable table) private static bool TextureColorTable(Texture* texture, out ColorTable.Table table)
{ {
if (texture == null) if (texture == null)
{ {
@ -92,6 +92,7 @@ public unsafe class DirectXService(IFramework framework) : IService
} }
catch catch
{ {
table = default;
return false; return false;
} }
} }
@ -114,7 +115,7 @@ public unsafe class DirectXService(IFramework framework) : IService
} }
/// <summary> Turn a mapped texture into a color table. </summary> /// <summary> Turn a mapped texture into a color table. </summary>
private static ColorTable GetTextureData(ID3D11Texture2D1 resource, MappedSubresource map) private static ColorTable.Table GetTextureData(ID3D11Texture2D1 resource, MappedSubresource map)
{ {
var desc = resource.Description1; var desc = resource.Description1;
@ -133,14 +134,14 @@ public unsafe class DirectXService(IFramework framework) : IService
/// <param name="height"> The height of the texture. (Needs to be 16).</param> /// <param name="height"> The height of the texture. (Needs to be 16).</param>
/// <param name="pitch"> The stride in the texture data. </param> /// <param name="pitch"> The stride in the texture data. </param>
/// <returns></returns> /// <returns></returns>
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. // Check that the data has sufficient dimension and size.
var expectedSize = sizeof(Half) * MaterialService.TextureWidth * height * 4; 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; return default;
var ret = new ColorTable(); var ret = new ColorTable.Table();
var target = (byte*)&ret; var target = (byte*)&ret;
// If the stride is the same as in the table, just copy. // If the stride is the same as in the table, just copy.
if (pitch == MaterialService.TextureWidth) if (pitch == MaterialService.TextureWidth)

View file

@ -13,11 +13,11 @@ public sealed unsafe class LiveColorTablePreviewer : IService, IDisposable
private readonly DirectXService _directXService; private readonly DirectXService _directXService;
public MaterialValueIndex LastValueIndex { get; private set; } = MaterialValueIndex.Invalid; 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 MaterialValueIndex _valueIndex = MaterialValueIndex.Invalid;
private ObjectIndex _lastObjectIndex = ObjectIndex.AnyIndex; private ObjectIndex _lastObjectIndex = ObjectIndex.AnyIndex;
private ObjectIndex _objectIndex = 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) 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; var table = LastOriginalColorTable;
if (_valueIndex.RowIndex != byte.MaxValue) if (_valueIndex.RowIndex != byte.MaxValue)
{ {
table[_valueIndex.RowIndex].Diffuse = diffuse; table[_valueIndex.RowIndex].DiffuseColor = (HalfColor)diffuse;
table[_valueIndex.RowIndex].Emissive = emissive; table[_valueIndex.RowIndex].EmissiveColor = (HalfColor)emissive;
} }
else else
{ {
for (var i = 0; i < ColorTable.NumRows; ++i) for (var i = 0; i < ColorTable.NumRows; ++i)
{ {
table[i].Diffuse = diffuse; table[i].DiffuseColor = (HalfColor)diffuse;
table[i].Emissive = emissive; table[i].EmissiveColor = (HalfColor)emissive;
} }
} }
@ -92,7 +92,7 @@ public sealed unsafe class LiveColorTablePreviewer : IService, IDisposable
_objectIndex = ObjectIndex.AnyIndex; _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) if (_valueIndex.DrawObject is not MaterialValueIndex.DrawObjectType.Invalid)
return; return;

View file

@ -75,7 +75,7 @@ public sealed unsafe class MaterialManager : IRequiredService, IDisposable
/// <summary> Update and apply the glamourer state of an actor according to the application sources when updated by the game. </summary> /// <summary> Update and apply the glamourer state of an actor according to the application sources when updated by the game. </summary>
private void UpdateMaterialValues(ActorState state, ReadOnlySpan<(uint Key, MaterialValueState Value)> values, CharacterWeapon drawData, private void UpdateMaterialValues(ActorState state, ReadOnlySpan<(uint Key, MaterialValueState Value)> values, CharacterWeapon drawData,
ref ColorTable colorTable) ref ColorTable.Table colorTable)
{ {
var deleteList = _deleteList.Value!; var deleteList = _deleteList.Value!;
deleteList.Clear(); deleteList.Clear();

View file

@ -13,7 +13,7 @@ public static unsafe class MaterialService
public const int TextureHeight = ColorTable.NumRows; public const int TextureHeight = ColorTable.NumRows;
public const int MaterialsPerModel = 10; 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]; var textureSize = stackalloc int[2];
textureSize[0] = TextureWidth; textureSize[0] = TextureWidth;
@ -24,7 +24,7 @@ public static unsafe class MaterialService
if (texture == null) if (texture == null)
return false; return false;
fixed (ColorTable* ptr = &colorTable) fixed (ColorTable.Table* ptr = &colorTable)
{ {
return texture->InitializeContents(ptr); return texture->InitializeContents(ptr);
} }
@ -53,7 +53,7 @@ public static unsafe class MaterialService
/// <param name="modelSlot"> The model slot. </param> /// <param name="modelSlot"> The model slot. </param>
/// <param name="materialSlot"> The material slot in the model. </param> /// <param name="materialSlot"> The material slot in the model. </param>
/// <returns> A pointer to the color table or null. </returns> /// <returns> A pointer to the color table or null. </returns>
public static ColorTable* GetMaterialColorTable(Model model, int modelSlot, byte materialSlot) public static ColorTable.Table* GetMaterialColorTable(Model model, int modelSlot, byte materialSlot)
{ {
if (!model.IsCharacterBase) if (!model.IsCharacterBase)
return null; return null;
@ -66,6 +66,6 @@ public static unsafe class MaterialService
if (material == null || material->ColorTable == null) if (material == null || material->ColorTable == null)
return null; return null;
return (ColorTable*)material->ColorTable; return (ColorTable.Table*)material->ColorTable;
} }
} }

View file

@ -21,8 +21,9 @@ public struct ColorRow(Vector3 diffuse, Vector3 specular, Vector3 emissive, floa
public float SpecularStrength = specularStrength; public float SpecularStrength = specularStrength;
public float GlossStrength = glossStrength; public float GlossStrength = glossStrength;
public ColorRow(in ColorTable.Row row) public ColorRow(in ColorTableRow row)
: this(Root(row.Diffuse), Root(row.Specular), Root(row.Emissive), row.SpecularStrength, row.GlossStrength) : 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) 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) private static float Root(float value)
=> value < 0 ? MathF.Sqrt(-value) : MathF.Sqrt(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 ret = false;
var d = Square(Diffuse); var d = Square(Diffuse);
if (!row.Diffuse.NearEqual(d)) if (!((Vector3)row.DiffuseColor).NearEqual(d))
{ {
row.Diffuse = d; row.DiffuseColor = (HalfColor)d;
ret = true; ret = true;
} }
var s = Square(Specular); var s = Square(Specular);
if (!row.Specular.NearEqual(s)) if (!((Vector3)row.SpecularColor).NearEqual(s))
{ {
row.Specular = s; row.SpecularColor = (HalfColor)s;
ret = true; ret = true;
} }
var e = Square(Emissive); var e = Square(Emissive);
if (!row.Emissive.NearEqual(e)) if (!((Vector3)row.EmissiveColor).NearEqual(e))
{ {
row.Emissive = e; row.EmissiveColor = (HalfColor)e;
ret = true; ret = true;
} }
if (!row.SpecularStrength.NearEqual(SpecularStrength)) if (!((float)row.SheenRate).NearEqual(SpecularStrength))
{ {
row.SpecularStrength = SpecularStrength; row.SheenRate = (Half)SpecularStrength;
ret = true; ret = true;
} }
if (!row.GlossStrength.NearEqual(GlossStrength)) if (!((float)row.Metalness).NearEqual(GlossStrength))
{ {
row.GlossStrength = GlossStrength; row.Metalness = (Half)GlossStrength;
ret = true; ret = true;
} }

View file

@ -66,7 +66,7 @@ public sealed unsafe class PrepareColorSet
} }
public static bool TryGetColorTable(MaterialResourceHandle* material, StainIds stainIds, public static bool TryGetColorTable(MaterialResourceHandle* material, StainIds stainIds,
out ColorTable table) out ColorTable.Table table)
{ {
if (material->ColorTable == null) if (material->ColorTable == null)
{ {
@ -74,7 +74,7 @@ public sealed unsafe class PrepareColorSet
return false; return false;
} }
var newTable = *(ColorTable*)material->ColorTable; var newTable = *(ColorTable.Table*)material->ColorTable;
if (GetDyeTable(material, out var dyeTable)) if (GetDyeTable(material, out var dyeTable))
{ {
if (stainIds.Stain1.Id != 0) if (stainIds.Stain1.Id != 0)
@ -91,11 +91,14 @@ public sealed unsafe class PrepareColorSet
} }
/// <summary> Assumes the actor is valid. </summary> /// <summary> Assumes the actor is valid. </summary>
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; var idx = index.SlotIndex * MaterialService.MaterialsPerModel + index.MaterialIndex;
if (!index.TryGetModel(actor, out var model)) if (!index.TryGetModel(actor, out var model))
{
table = default;
return false; return false;
}
var handle = (MaterialResourceHandle*)model.AsCharacterBase->Materials[idx]; var handle = (MaterialResourceHandle*)model.AsCharacterBase->Materials[idx];
if (handle == null) if (handle == null)

@ -1 +1 @@
Subproject commit ad6973c559b4c05aa3c3735ec7b53cc0f5d2f203 Subproject commit 016da3c2219a3dbe4c2841ae0d1305ae0b2ad60f