diff --git a/Glamourer/Gui/Materials/MaterialDrawer.cs b/Glamourer/Gui/Materials/MaterialDrawer.cs index b5f9d58..aeb4a9b 100644 --- a/Glamourer/Gui/Materials/MaterialDrawer.cs +++ b/Glamourer/Gui/Materials/MaterialDrawer.cs @@ -3,124 +3,159 @@ using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using Glamourer.Designs; using Glamourer.Interop.Material; -using Glamourer.Interop.Structs; -using Glamourer.State; using ImGuiNET; using OtterGui; using OtterGui.Services; using Penumbra.GameData.Enums; using Penumbra.GameData.Files; using Penumbra.GameData.Gui; -using Penumbra.GameData.Structs; -using Vortice.DXGI; namespace Glamourer.Gui.Materials; -public unsafe class MaterialDrawer(StateManager _stateManager, DesignManager _designManager, Configuration _config) : IService +public class MaterialDrawer(DesignManager _designManager, Configuration _config) : IService { - private ActorState? _state; + public const float GlossWidth = 100; + public const float SpecularStrengthWidth = 125; + private EquipSlot _newSlot = EquipSlot.Head; private int _newMaterialIdx; private int _newRowIdx; - private MaterialValueIndex _newKey = MaterialValueIndex.Min(); + private MaterialValueIndex _newKey = MaterialValueIndex.FromSlot(EquipSlot.Head); - public void DrawDesignPanel(Design design) + private Vector2 _buttonSize; + private float _spacing; + + public void Draw(Design design) { - var buttonSize = new Vector2(ImGui.GetFrameHeight()); - using (var table = ImRaii.Table("table", 5, ImGuiTableFlags.RowBg)) + var available = ImGui.GetContentRegionAvail().X; + _spacing = ImGui.GetStyle().ItemInnerSpacing.X; + _buttonSize = new Vector2(ImGui.GetFrameHeight()); + var colorWidth = 4 * _buttonSize.X + + (GlossWidth + SpecularStrengthWidth) * ImGuiHelpers.GlobalScale + + 6 * _spacing + + ImGui.CalcTextSize("Revert").X; + if (available > 1.95 * colorWidth) + DrawSingleRow(design); + else + DrawTwoRow(design); + DrawNew(design); + } + + private void DrawName(MaterialValueIndex index) + { + using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale).Push(ImGuiStyleVar.ButtonTextAlign, new Vector2(0, 0.5f)); + using var color = ImRaii.PushColor(ImGuiCol.Border, ImGui.GetColorU32(ImGuiCol.Text)); + ImGuiUtil.DrawTextButton(index.ToString(), new Vector2((GlossWidth + SpecularStrengthWidth) * ImGuiHelpers.GlobalScale + _spacing, 0), 0); + } + + private void DrawSingleRow(Design design) + { + for (var i = 0; i < design.Materials.Count; ++i) { - if (!table) - return; + using var id = ImRaii.PushId(i); + var (idx, value) = design.Materials[i]; + var key = MaterialValueIndex.FromKey(idx); - ImGui.TableSetupColumn("buttons", ImGuiTableColumnFlags.WidthFixed, buttonSize.X * 3 + 2 * ImGui.GetStyle().ItemInnerSpacing.X); - ImGui.TableSetupColumn("enabled", ImGuiTableColumnFlags.WidthFixed, buttonSize.X); - ImGui.TableSetupColumn("values", ImGuiTableColumnFlags.WidthFixed, - ImGui.GetStyle().ItemInnerSpacing.X * 4 + 3 * buttonSize.X + 220 * ImGuiHelpers.GlobalScale); - ImGui.TableSetupColumn("revert", ImGuiTableColumnFlags.WidthFixed, buttonSize.X + ImGui.CalcTextSize("Revertm").X); - ImGui.TableSetupColumn("slot", ImGuiTableColumnFlags.WidthStretch); - - for (var i = 0; i < design.Materials.Count; ++i) - { - var (idx, value) = design.Materials[i]; - var key = MaterialValueIndex.FromKey(idx); - var name = key.DrawObject switch - { - MaterialValueIndex.DrawObjectType.Human => ((uint)key.SlotIndex).ToEquipSlot().ToName(), - MaterialValueIndex.DrawObjectType.Mainhand => EquipSlot.MainHand.ToName(), - MaterialValueIndex.DrawObjectType.Offhand => EquipSlot.OffHand.ToName(), - _ => string.Empty, - }; - if (name.Length == 0) - continue; - - name = $"{name} Material #{key.MaterialIndex + 1} Row #{key.RowIndex + 1}"; - using var id = ImRaii.PushId((int)idx); - var deleteEnabled = _config.DeleteDesignModifier.IsActive(); - ImGui.TableNextColumn(); - if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), buttonSize, - $"Delete this color row.{(deleteEnabled ? string.Empty : $"\nHold {_config.DeleteDesignModifier} to delete.")}", - !deleteEnabled, true)) - { - _designManager.ChangeMaterialValue(design, key, null); - --i; - } - - ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X); - if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Clipboard.ToIconString(), buttonSize, "Export this row to your clipboard.", - false, - true)) - ColorRowClipboard.Row = value.Value; - - ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X); - if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Paste.ToIconString(), buttonSize, - "Import an exported row from your clipboard onto this row.", !ColorRowClipboard.IsSet, true)) - _designManager.ChangeMaterialValue(design, key, ColorRowClipboard.Row); - - ImGui.TableNextColumn(); - var enabled = value.Enabled; - if (ImGui.Checkbox("Enabled", ref enabled)) - _designManager.ChangeApplyMaterialValue(design, key, enabled); - - ImGui.TableNextColumn(); - var revert = value.Revert; - using (ImRaii.Disabled(revert)) - { - var row = value.Value; - DrawRow(design, key, row); - } - - ImGui.TableNextColumn(); - - if (ImGui.Checkbox("Revert", ref revert)) - _designManager.ChangeMaterialRevert(design, key, revert); - ImGuiUtil.HoverTooltip( - "If this is checked, Glamourer will try to revert the advanced dye row to its game state instead of applying a specific row."); - - ImGui.TableNextColumn(); - ImGui.TextUnformatted(name); - } + DrawName(key); + ImGui.SameLine(0, _spacing); + DeleteButton(design, key, ref i); + ImGui.SameLine(0, _spacing); + CopyButton(value.Value); + ImGui.SameLine(0, _spacing); + PasteButton(design, key); + ImGui.SameLine(0, _spacing); + EnabledToggle(design, key, value.Enabled); + ImGui.SameLine(0, _spacing); + DrawRow(design, key, value.Value, value.Revert); + ImGui.SameLine(0, _spacing); + RevertToggle(design, key, value.Revert); } + } - var exists = design.GetMaterialDataRef().TryGetValue(_newKey, out _); - if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), buttonSize, - exists ? "The selected advanced dye row already exists." : "Add the selected advanced dye row.", exists, true)) - _designManager.ChangeMaterialValue(design, _newKey, ColorRow.Empty); + private void DrawTwoRow(Design design) + { + for (var i = 0; i < design.Materials.Count; ++i) + { + using var id = ImRaii.PushId(i); + var (idx, value) = design.Materials[i]; + var key = MaterialValueIndex.FromKey(idx); - ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X); + DrawName(key); + ImGui.SameLine(0, _spacing); + DeleteButton(design, key, ref i); + ImGui.SameLine(0, _spacing); + CopyButton(value.Value); + ImGui.SameLine(0, _spacing); + PasteButton(design, key); + ImGui.SameLine(0, _spacing); + EnabledToggle(design, key, value.Enabled); + + + DrawRow(design, key, value.Value, value.Revert); + ImGui.SameLine(0, _spacing); + RevertToggle(design, key, value.Revert); + ImGui.Separator(); + } + } + + private void DeleteButton(Design design, MaterialValueIndex index, ref int idx) + { + var deleteEnabled = _config.DeleteDesignModifier.IsActive(); + if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), _buttonSize, + $"Delete this color row.{(deleteEnabled ? string.Empty : $"\nHold {_config.DeleteDesignModifier} to delete.")}", + !deleteEnabled, true)) + return; + + _designManager.ChangeMaterialValue(design, index, null); + --idx; + } + + private void CopyButton(in ColorRow row) + { + if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Clipboard.ToIconString(), _buttonSize, "Export this row to your clipboard.", + false, + true)) + ColorRowClipboard.Row = row; + } + + private void PasteButton(Design design, MaterialValueIndex index) + { + if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Paste.ToIconString(), _buttonSize, + "Import an exported row from your clipboard onto this row.", !ColorRowClipboard.IsSet, true)) + _designManager.ChangeMaterialValue(design, index, ColorRowClipboard.Row); + } + + private void EnabledToggle(Design design, MaterialValueIndex index, bool enabled) + { + if (ImGui.Checkbox("Enabled", ref enabled)) + _designManager.ChangeApplyMaterialValue(design, index, enabled); + } + + private void RevertToggle(Design design, MaterialValueIndex index, bool revert) + { + if (ImGui.Checkbox("Revert", ref revert)) + _designManager.ChangeMaterialRevert(design, index, revert); + ImGuiUtil.HoverTooltip( + "If this is checked, Glamourer will try to revert the advanced dye row to its game state instead of applying a specific row."); + } + + public void DrawNew(Design design) + { if (EquipSlotCombo.Draw("##slot", "Choose a slot for an advanced dye row.", ref _newSlot)) - _newKey = _newSlot switch + _newKey = MaterialValueIndex.FromSlot(_newSlot) with { - EquipSlot.MainHand => new MaterialValueIndex(MaterialValueIndex.DrawObjectType.Mainhand, 0, (byte)_newMaterialIdx, - (byte)_newRowIdx), - EquipSlot.OffHand => new MaterialValueIndex(MaterialValueIndex.DrawObjectType.Offhand, 0, (byte)_newMaterialIdx, - (byte)_newRowIdx), - _ => new MaterialValueIndex(MaterialValueIndex.DrawObjectType.Human, (byte)_newSlot.ToIndex(), (byte)_newMaterialIdx, - (byte)_newRowIdx), + MaterialIndex = (byte)_newMaterialIdx, + RowIndex = (byte)_newRowIdx, }; ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X); DrawMaterialIdxDrag(); ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X); DrawRowIdxDrag(); + ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X); + var exists = design.GetMaterialDataRef().TryGetValue(_newKey, out _); + if (ImGuiUtil.DrawDisabledButton("Add New Row", Vector2.Zero, + exists ? "The selected advanced dye row already exists." : "Add the selected advanced dye row.", exists, false)) + _designManager.ChangeMaterialValue(design, _newKey, ColorRow.Empty); } private void DrawMaterialIdxDrag() @@ -149,131 +184,24 @@ public unsafe class MaterialDrawer(StateManager _stateManager, DesignManager _de _newRowIdx -= 1; } - public void DrawActorPanel(Actor actor) + private void DrawRow(Design design, MaterialValueIndex index, in ColorRow row, bool disabled) { - if (!actor.IsCharacter || !_stateManager.GetOrCreate(actor, out _state)) - return; - - var model = actor.Model; - if (!model.IsHuman) - return; - - if (model.AsCharacterBase->SlotCount < 10) - return; - - // Humans should have at least 10 slots for the equipment types. Technically more. - foreach (var (slot, idx) in EquipSlotExtensions.EqdpSlots.WithIndex()) - { - var item = model.GetArmor(slot).ToWeapon(0); - DrawSlotMaterials(model, slot.ToName(), item, new MaterialValueIndex(MaterialValueIndex.DrawObjectType.Human, (byte)idx, 0, 0)); - } - - var (mainhand, offhand, mh, oh) = actor.Model.GetWeapons(actor); - if (mainhand.IsWeapon && mainhand.AsCharacterBase->SlotCount > 0) - DrawSlotMaterials(mainhand, EquipSlot.MainHand.ToName(), mh, - new MaterialValueIndex(MaterialValueIndex.DrawObjectType.Mainhand, 0, 0, 0)); - if (offhand.IsWeapon && offhand.AsCharacterBase->SlotCount > 0) - DrawSlotMaterials(offhand, EquipSlot.OffHand.ToName(), oh, - new MaterialValueIndex(MaterialValueIndex.DrawObjectType.Offhand, 0, 0, 0)); - } - - - private void DrawSlotMaterials(Model model, string name, CharacterWeapon drawData, MaterialValueIndex index) - { - for (byte materialIndex = 0; materialIndex < MaterialService.MaterialsPerModel; ++materialIndex) - { - var texture = model.AsCharacterBase->ColorTableTextures + index.SlotIndex * MaterialService.MaterialsPerModel + materialIndex; - if (*texture == null) - continue; - - if (!DirectXTextureHelper.TryGetColorTable(*texture, out var table)) - continue; - - using var tree = ImRaii.TreeNode($"{name} Material #{materialIndex + 1}###{name}{materialIndex}"); - if (!tree) - continue; - - DrawMaterial(ref table, drawData, index with { MaterialIndex = materialIndex }); - } - } - - private void DrawMaterial(ref MtrlFile.ColorTable table, CharacterWeapon drawData, MaterialValueIndex sourceIndex) - { - for (byte i = 0; i < MtrlFile.ColorTable.NumRows; ++i) - { - var index = sourceIndex with { RowIndex = i }; - ref var row = ref table[i]; - DrawRow(ref row, drawData, index); - } - } - - private void DrawRow(Design design, MaterialValueIndex index, in ColorRow row) - { - var spacing = ImGui.GetStyle().ItemInnerSpacing; - var tmp = row; + var tmp = row; + using var _ = ImRaii.Disabled(disabled); var applied = ImGuiUtil.ColorPicker("##diffuse", "Change the diffuse value for this row.", row.Diffuse, v => tmp.Diffuse = v, "D"); - ImGui.SameLine(0, spacing.X); + ImGui.SameLine(0, _spacing); applied |= ImGuiUtil.ColorPicker("##specular", "Change the specular value for this row.", row.Specular, v => tmp.Specular = v, "S"); - ImGui.SameLine(0, spacing.X); + ImGui.SameLine(0, _spacing); applied |= ImGuiUtil.ColorPicker("##emissive", "Change the emissive value for this row.", row.Emissive, v => tmp.Emissive = v, "E"); - ImGui.SameLine(0, spacing.X); - ImGui.SetNextItemWidth(100 * ImGuiHelpers.GlobalScale); + ImGui.SameLine(0, _spacing); + ImGui.SetNextItemWidth(GlossWidth * ImGuiHelpers.GlobalScale); applied |= ImGui.DragFloat("##Gloss", ref tmp.GlossStrength, 0.01f, 0.001f, float.MaxValue, "%.3f G"); ImGuiUtil.HoverTooltip("Change the gloss strength for this row."); - ImGui.SameLine(0, spacing.X); - ImGui.SetNextItemWidth(120 * ImGuiHelpers.GlobalScale); + ImGui.SameLine(0, _spacing); + ImGui.SetNextItemWidth(SpecularStrengthWidth * ImGuiHelpers.GlobalScale); applied |= ImGui.DragFloat("##Specular Strength", ref tmp.SpecularStrength, 0.01f, float.MinValue, float.MaxValue, "%.3f SS"); ImGuiUtil.HoverTooltip("Change the specular strength for this row."); if (applied) _designManager.ChangeMaterialValue(design, index, tmp); } - - private void DrawRow(ref MtrlFile.ColorTable.Row row, CharacterWeapon drawData, MaterialValueIndex index) - { - using var id = ImRaii.PushId(index.RowIndex); - var changed = _state!.Materials.TryGetValue(index, out var value); - if (!changed) - { - var internalRow = new ColorRow(row); - value = new MaterialValueState(internalRow, internalRow, drawData, StateSource.Manual); - } - - ImGui.AlignTextToFramePadding(); - using (ImRaii.PushFont(UiBuilder.MonoFont)) - { - ImGui.TextUnformatted($"Row {index.RowIndex + 1:D2}"); - } - - ImGui.SameLine(0, ImGui.GetStyle().ItemSpacing.X * 2); - var applied = ImGuiUtil.ColorPicker("##diffuse", "Change the diffuse value for this row.", value.Model.Diffuse, - v => value.Model.Diffuse = v, "D"); - - var spacing = ImGui.GetStyle().ItemInnerSpacing; - ImGui.SameLine(0, spacing.X); - applied |= ImGuiUtil.ColorPicker("##specular", "Change the specular value for this row.", value.Model.Specular, - v => value.Model.Specular = v, "S"); - ImGui.SameLine(0, spacing.X); - applied |= ImGuiUtil.ColorPicker("##emissive", "Change the emissive value for this row.", value.Model.Emissive, - v => value.Model.Emissive = v, "E"); - ImGui.SameLine(0, spacing.X); - ImGui.SetNextItemWidth(100 * ImGuiHelpers.GlobalScale); - applied |= ImGui.DragFloat("##Gloss", ref value.Model.GlossStrength, 0.01f, 0.001f, float.MaxValue, "%.3f G") - && value.Model.GlossStrength > 0; - ImGuiUtil.HoverTooltip("Change the gloss strength for this row."); - ImGui.SameLine(0, spacing.X); - ImGui.SetNextItemWidth(100 * ImGuiHelpers.GlobalScale); - applied |= ImGui.DragFloat("##Specular Strength", ref value.Model.SpecularStrength, 0.01f, float.MinValue, float.MaxValue, "%.3f SS"); - ImGuiUtil.HoverTooltip("Change the specular strength for this row."); - if (applied) - _stateManager.ChangeMaterialValue(_state!, index, value, ApplySettings.Manual); - if (changed) - { - ImGui.SameLine(0, spacing.X); - using (ImRaii.PushFont(UiBuilder.IconFont)) - { - using var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.FavoriteStarOn.Value()); - ImGui.TextUnformatted(FontAwesomeIcon.UserEdit.ToIconString()); - } - } - } } diff --git a/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs b/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs index 25b71b3..dc97acb 100644 --- a/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs +++ b/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs @@ -9,7 +9,6 @@ using Glamourer.Gui.Customization; using Glamourer.Gui.Equipment; using Glamourer.Gui.Materials; using Glamourer.Interop; -using Glamourer.Interop.Material; using Glamourer.Interop.Structs; using Glamourer.State; using ImGuiNET; @@ -36,7 +35,6 @@ public class ActorPanel( ICondition _conditions, DictModelChara _modelChara, CustomizeParameterDrawer _parameterDrawer, - MaterialDrawer _materialDrawer, AdvancedDyePopup _advancedDyes) { private ActorIdentifier _identifier; diff --git a/Glamourer/Gui/Tabs/DebugTab/ModelEvaluationPanel.cs b/Glamourer/Gui/Tabs/DebugTab/ModelEvaluationPanel.cs index 8e93877..81c9766 100644 --- a/Glamourer/Gui/Tabs/DebugTab/ModelEvaluationPanel.cs +++ b/Glamourer/Gui/Tabs/DebugTab/ModelEvaluationPanel.cs @@ -53,8 +53,6 @@ public unsafe class ModelEvaluationPanel( ImGui.TextUnformatted($"Transformation Id: {actor.AsCharacter->CharacterData.TransformationId}"); if (actor.AsCharacter->CharacterData.ModelCharaId_2 != -1) ImGui.TextUnformatted($"ModelChara2 {actor.AsCharacter->CharacterData.ModelCharaId_2}"); - if (actor.AsCharacter->CharacterData.StatusEffectVFXId != 0) - ImGui.TextUnformatted($"Status Id: {actor.AsCharacter->CharacterData.StatusEffectVFXId}"); } ImGuiUtil.DrawTableColumn("Mainhand"); diff --git a/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs b/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs index 168f994..1e3e468 100644 --- a/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs +++ b/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs @@ -185,7 +185,7 @@ public class DesignPanel( if (!h) return; - _materials.DrawDesignPanel(_selector.Selected!); + _materials.Draw(_selector.Selected!); } private void DrawCustomizeApplication() diff --git a/OtterGui b/OtterGui index 75c5a7b..9d68a48 160000 --- a/OtterGui +++ b/OtterGui @@ -1 +1 @@ -Subproject commit 75c5a7b220e7f799f85741288e3de4a20af9bcf4 +Subproject commit 9d68a487610266058fbec853efed9a35c9df6fbe diff --git a/Penumbra.GameData b/Penumbra.GameData index 5825baf..44021b9 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit 5825bafb0602cf8a252581f21291c0d27e5561f0 +Subproject commit 44021b93e6901c84b739bbf4d1c6350f4486cdbf