Finish advanced dye UI for now.

This commit is contained in:
Ottermandias 2024-02-17 13:49:08 +01:00
parent 59529476eb
commit a5509e8ba0
6 changed files with 138 additions and 214 deletions

View file

@ -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());
}
}
}
}

View file

@ -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;

View file

@ -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");

View file

@ -185,7 +185,7 @@ public class DesignPanel(
if (!h)
return;
_materials.DrawDesignPanel(_selector.Selected!);
_materials.Draw(_selector.Selected!);
}
private void DrawCustomizeApplication()

@ -1 +1 @@
Subproject commit 75c5a7b220e7f799f85741288e3de4a20af9bcf4
Subproject commit 9d68a487610266058fbec853efed9a35c9df6fbe

@ -1 +1 @@
Subproject commit 5825bafb0602cf8a252581f21291c0d27e5561f0
Subproject commit 44021b93e6901c84b739bbf4d1c6350f4486cdbf