diff --git a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ColorTable.cs b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ColorTable.cs index 144a1198..cbf7d5e2 100644 --- a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ColorTable.cs +++ b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ColorTable.cs @@ -252,7 +252,8 @@ public partial class MtrlTab return ret; } - private static bool DrawColors(ColorTable table, ColorDyeTable? dyeTable, DyePack? dyePack, int rowIdx) + private static bool DrawColors(IColorTable table, IColorDyeTable? dyeTable, TDyePack? dyePack, int rowIdx) + where TRow : unmanaged, IColorRow where TDyeRow : unmanaged, IColorDyeRow where TDyePack : unmanaged, IDyePack { var dyeOffset = ImGui.GetContentRegionAvail().X + ImGui.GetStyle().ItemSpacing.X diff --git a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.CommonColorTable.cs b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.CommonColorTable.cs index 7d8e2cf2..a9dce2ee 100644 --- a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.CommonColorTable.cs +++ b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.CommonColorTable.cs @@ -50,9 +50,9 @@ public partial class MtrlTab ret |= Mtrl.Table switch { - LegacyColorTable legacyTable => DrawLegacyColorTable(legacyTable, Mtrl.DyeTable as LegacyColorDyeTable, disabled), + LegacyColorTable legacyTable => DrawLegacyColorTable(legacyTable, Mtrl.DyeTable as LegacyColorDyeTable, disabled, uiState), ColorTable table when Mtrl.ShaderPackage.Name is "characterlegacy.shpk" => DrawLegacyColorTable(table, - Mtrl.DyeTable as ColorDyeTable, disabled), + Mtrl.DyeTable as ColorDyeTable, disabled, uiState), ColorTable table => DrawColorTable(table, Mtrl.DyeTable as ColorDyeTable, disabled, uiState), _ => false, }; diff --git a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.LegacyColorTable.cs b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.LegacyColorTable.cs index 52280487..f3ca43b9 100644 --- a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.LegacyColorTable.cs +++ b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.LegacyColorTable.cs @@ -1,7 +1,5 @@ -using Dalamud.Interface; using Dalamud.Interface.Utility.Raii; using ImGuiNET; -using OtterGui; using OtterGui.Text; using Penumbra.GameData.Files.MaterialStructs; using Penumbra.GameData.Files.StainMapStructs; @@ -11,247 +9,197 @@ namespace Penumbra.UI.AdvancedWindow.Materials; public partial class MtrlTab { - private const float LegacyColorTableFloatSize = 65.0f; - private const float LegacyColorTablePercentageSize = 50.0f; - private const float LegacyColorTableIntegerSize = 40.0f; - private const float LegacyColorTableByteSize = 25.0f; - - private bool DrawLegacyColorTable(IColorTable table, IColorDyeTable? dyeTable, bool disabled) + private bool DrawLegacyColorTable(IColorTable table, IColorDyeTable? dyeTable, bool disabled, MtrlTabUiState uiState) where TRow : unmanaged, ILegacyColorRow where TDyeRow : unmanaged, ILegacyColorDyeRow { - using var imTable = ImUtf8.Table("##ColorTable"u8, dyeTable != null ? 10 : 8, - ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg | ImGuiTableFlags.BordersInnerV); - if (!imTable) - return false; + DrawColorTablePairSelector(table, disabled, uiState); + return DrawLegacyColorTablePairEditor(table, dyeTable, disabled, uiState); + } - DrawLegacyColorTableHeader(dyeTable != null); - - var ret = false; - for (var i = 0; i < ColorTable.NumRows; ++i) + private bool DrawLegacyColorTablePairEditor(IColorTable table, IColorDyeTable? dyeTable, bool disabled, MtrlTabUiState uiState) + where TRow : unmanaged, ILegacyColorRow where TDyeRow : unmanaged, ILegacyColorDyeRow + { + var retA = false; + var retB = false; + var rowAIdx = uiState.ColorTableSelectedPair << 1; + var rowBIdx = rowAIdx | 1; + var dyeA = dyeTable?[uiState.ColorTableSelectedPair << 1] ?? default; + var dyeB = dyeTable?[(uiState.ColorTableSelectedPair << 1) | 1] ?? default; + var previewDyeA = _stainService.GetStainCombo(dyeA.Channel).CurrentSelection.Key; + var previewDyeB = _stainService.GetStainCombo(dyeB.Channel).CurrentSelection.Key; + var dyePackA = _stainService.LegacyStmFile.GetValueOrNull(dyeA.Template, previewDyeA); + var dyePackB = _stainService.LegacyStmFile.GetValueOrNull(dyeB.Template, previewDyeB); + using (var columns = ImUtf8.Columns(2, "ColorTable"u8)) { - if (DrawLegacyColorTableRow(table, dyeTable, i, disabled)) + using (ImUtf8.PushId("RowHeaderA"u8)) { - UpdateColorTableRowPreview(i); - ret = true; + retA |= DrawRowHeader(rowAIdx, disabled); + } + columns.Next(); + using (ImUtf8.PushId("RowHeaderB"u8)) + { + retB |= DrawRowHeader(rowBIdx, disabled); + } + } + + DrawHeader(" Colors"u8); + using (var columns = ImUtf8.Columns(2, "ColorTable"u8)) + { + using var dis = ImRaii.Disabled(disabled); + using (ImUtf8.PushId("ColorsA"u8)) + { + retA |= DrawColors(table, dyeTable, dyePackA, rowAIdx); } - ImGui.TableNextRow(); + columns.Next(); + using (ImUtf8.PushId("ColorsB"u8)) + { + retB |= DrawColors(table, dyeTable, dyePackB, rowBIdx); + } } - return ret; - } - - private static void DrawLegacyColorTableHeader(bool hasDyeTable) - { - ImGui.TableNextColumn(); - ImUtf8.TableHeader(default(ReadOnlySpan)); - ImGui.TableNextColumn(); - ImUtf8.TableHeader("Row"u8); - ImGui.TableNextColumn(); - ImUtf8.TableHeader("Diffuse"u8); - ImGui.TableNextColumn(); - ImUtf8.TableHeader("Specular"u8); - ImGui.TableNextColumn(); - ImUtf8.TableHeader("Emissive"u8); - ImGui.TableNextColumn(); - ImUtf8.TableHeader("Gloss"u8); - ImGui.TableNextColumn(); - ImUtf8.TableHeader("Tile"u8); - ImGui.TableNextColumn(); - ImUtf8.TableHeader("Repeat / Skew"u8); - if (hasDyeTable) + DrawHeader(" Specular Parameters"u8); + using (var columns = ImUtf8.Columns(2, "ColorTable"u8)) { - ImGui.TableNextColumn(); - ImUtf8.TableHeader("Dye"u8); - ImGui.TableNextColumn(); - ImUtf8.TableHeader("Dye Preview"u8); + using var dis = ImRaii.Disabled(disabled); + using (ImUtf8.PushId("SpecularA"u8)) + { + retA |= DrawLegacySpecular(table, dyeTable, dyePackA, rowAIdx); + } + + columns.Next(); + using (ImUtf8.PushId("SpecularB"u8)) + { + retB |= DrawLegacySpecular(table, dyeTable, dyePackB, rowBIdx); + } } + + DrawHeader(" Material Template"u8); + using (var columns = ImUtf8.Columns(2, "ColorTable"u8)) + { + using var dis = ImRaii.Disabled(disabled); + using (ImUtf8.PushId("TemplateA"u8)) + { + retA |= DrawTemplateTile(table, rowAIdx); + } + + columns.Next(); + using (ImUtf8.PushId("TemplateB"u8)) + { + retB |= DrawTemplateTile(table, rowBIdx); + } + } + + if (dyeTable != null) + { + DrawHeader(" Dye Properties"u8); + using var columns = ImUtf8.Columns(2, "ColorTable"u8); + using var dis = ImRaii.Disabled(disabled); + using (ImUtf8.PushId("DyeA"u8)) + { + retA |= DrawLegacyDye(dyeTable, dyePackA, rowAIdx); + } + + columns.Next(); + using (ImUtf8.PushId("DyeB"u8)) + { + retB |= DrawLegacyDye(dyeTable, dyePackB, rowBIdx); + } + } + + if (retA) + UpdateColorTableRowPreview(rowAIdx); + if (retB) + UpdateColorTableRowPreview(rowBIdx); + + return retA | retB; } - private bool DrawLegacyColorTableRow(IColorTable table, IColorDyeTable? dyeTable, int rowIdx, bool disabled) + private static bool DrawLegacySpecular(IColorTable table, IColorDyeTable? dyeTable, LegacyDyePack? dyePack, int rowIdx) where TRow : unmanaged, ILegacyColorRow where TDyeRow : unmanaged, ILegacyColorDyeRow { - using var id = ImRaii.PushId(rowIdx); - ref var row = ref table[rowIdx]; - var dye = dyeTable?[rowIdx] ?? default; - var floatSize = LegacyColorTableFloatSize * UiHelpers.Scale; - var pctSize = LegacyColorTablePercentageSize * UiHelpers.Scale; - var intSize = LegacyColorTableIntegerSize * UiHelpers.Scale; - var byteSize = LegacyColorTableByteSize * UiHelpers.Scale; - ImGui.TableNextColumn(); - ColorTableCopyClipboardButton(rowIdx); - ImUtf8.SameLineInner(); - var ret = ColorTablePasteFromClipboardButton(rowIdx, disabled); - ImUtf8.SameLineInner(); - ColorTableRowHighlightButton(rowIdx, disabled); + var scalarSize = ColorTableScalarSize * UiHelpers.Scale; + var subColWidth = CalculateSubColumnWidth(2) + ImGui.GetStyle().ItemSpacing.X; + var dyeOffset = subColWidth + - ImGui.GetStyle().ItemSpacing.X * 2.0f + - ImGui.GetStyle().ItemInnerSpacing.X + - ImGui.GetFrameHeight() + - scalarSize; - ImGui.TableNextColumn(); - using (ImRaii.PushFont(UiBuilder.MonoFont)) - { - ImUtf8.Text($"{(rowIdx >> 1) + 1,2:D}{"AB"[rowIdx & 1]}"); - } + var ret = false; + ref var row = ref table[rowIdx]; + var dye = dyeTable?[rowIdx] ?? default; - ImGui.TableNextColumn(); - using var dis = ImRaii.Disabled(disabled); - ret |= CtColorPicker("##Diffuse"u8, "Diffuse Color"u8, row.DiffuseColor, - c => table[rowIdx].DiffuseColor = c); - if (dyeTable != null) - { - ImUtf8.SameLineInner(); - ret |= CtApplyStainCheckbox("##dyeDiffuse"u8, "Apply Diffuse Color on Dye"u8, dye.DiffuseColor, - b => dyeTable[rowIdx].DiffuseColor = b); - } - - ImGui.TableNextColumn(); - ret |= CtColorPicker("##Specular"u8, "Specular Color"u8, row.SpecularColor, - c => table[rowIdx].SpecularColor = c); - if (dyeTable != null) - { - ImUtf8.SameLineInner(); - ret |= CtApplyStainCheckbox("##dyeSpecular"u8, "Apply Specular Color on Dye"u8, dye.SpecularColor, - b => dyeTable[rowIdx].SpecularColor = b); - } - - ImGui.SameLine(); - ImGui.SetNextItemWidth(pctSize); - ret |= CtDragScalar("##SpecularMask"u8, "Specular Strength"u8, (float)row.SpecularMask * 100.0f, "%.0f%%"u8, 0f, HalfMaxValue * 100.0f, 1.0f, + ImGui.SetNextItemWidth(scalarSize); + ret |= CtDragScalar("Specular Strength"u8, default, (float)row.SpecularMask * 100.0f, "%.0f%%"u8, 0.0f, HalfMaxValue * 100.0f, + 1.0f, v => table[rowIdx].SpecularMask = (Half)(v * 0.01f)); if (dyeTable != null) { - ImUtf8.SameLineInner(); + ImGui.SameLine(dyeOffset); ret |= CtApplyStainCheckbox("##dyeSpecularMask"u8, "Apply Specular Strength on Dye"u8, dye.SpecularMask, b => dyeTable[rowIdx].SpecularMask = b); - } - - ImGui.TableNextColumn(); - ret |= CtColorPicker("##Emissive"u8, "Emissive Color"u8, row.EmissiveColor, - c => table[rowIdx].EmissiveColor = c); - if (dyeTable != null) - { ImUtf8.SameLineInner(); - ret |= CtApplyStainCheckbox("##dyeEmissive"u8, "Apply Emissive Color on Dye"u8, dye.EmissiveColor, - b => dyeTable[rowIdx].EmissiveColor = b); + ImGui.SetNextItemWidth(scalarSize); + CtDragScalar("##dyePreviewSpecularMask"u8, "Dye Preview for Specular Strength"u8, (float?)dyePack?.SpecularMask * 100.0f, "%.0f%%"u8); } - ImGui.TableNextColumn(); - ImGui.SetNextItemWidth(floatSize); - var glossStrengthMin = ImGui.GetIO().KeyCtrl ? 0.0f : HalfEpsilon; - ret |= CtDragHalf("##Shininess"u8, "Gloss Strength"u8, row.Shininess, "%.1f"u8, glossStrengthMin, HalfMaxValue, + ImGui.SameLine(subColWidth); + ImGui.SetNextItemWidth(scalarSize); + var shininessMin = ImGui.GetIO().KeyCtrl ? 0.0f : HalfEpsilon; + ret |= CtDragHalf("Gloss"u8, default, row.Shininess, "%.1f"u8, shininessMin, HalfMaxValue, Math.Max(0.1f, (float)row.Shininess * 0.025f), v => table[rowIdx].Shininess = v); - if (dyeTable != null) { - ImUtf8.SameLineInner(); - ret |= CtApplyStainCheckbox("##dyeShininess"u8, "Apply Gloss Strength on Dye"u8, dye.Shininess, + ImGui.SameLine(subColWidth + dyeOffset); + ret |= CtApplyStainCheckbox("##dyeShininess"u8, "Apply Gloss on Dye"u8, dye.Shininess, b => dyeTable[rowIdx].Shininess = b); - } - - ImGui.TableNextColumn(); - ImGui.SetNextItemWidth(intSize); - ret |= CtTileIndexPicker("##TileIndex"u8, "Tile Index"u8, row.TileIndex, true, - value => table[rowIdx].TileIndex = value); - ImUtf8.SameLineInner(); - ImGui.SetNextItemWidth(pctSize); - if (table is ColorTable rwTable) - { - ret |= CtDragScalar("##TileAlpha"u8, "Tile Opacity"u8, (float)row.TileAlpha * 100.0f, "%.0f%%"u8, 0f, HalfMaxValue * 100.0f, 1.0f, - v => rwTable[rowIdx].TileAlpha = (Half)(v * 0.01f)); - } - else - CtDragScalar("##TileAlpha"u8, "Tile Opacity"u8, (float)row.TileAlpha * 100.0f, "%.0f%%"u8); - - ImGui.TableNextColumn(); - ret |= CtTileTransformMatrix(row.TileTransform, floatSize, false, - m => table[rowIdx].TileTransform = m); - - if (dyeTable != null) - { - ImGui.TableNextColumn(); - ImGui.SetNextItemWidth(byteSize); - if (dyeTable is ColorDyeTable rwDyeTable) - { - ret |= CtDragScalar("##DyeChannel"u8, "Dye Channel"u8, dye.Channel + 1, "%d"u8, 1, StainService.ChannelCount, 0.25f, - value => rwDyeTable[rowIdx].Channel = (byte)(Math.Clamp(value, 1, StainService.ChannelCount) - 1)); - } - else - CtDragScalar("##DyeChannel"u8, "Dye Channel"u8, dye.Channel + 1, "%d"u8); ImUtf8.SameLineInner(); - _stainService.LegacyTemplateCombo.CurrentDyeChannel = dye.Channel; - if (_stainService.LegacyTemplateCombo.Draw("##dyeTemplate", dye.Template.ToString(), string.Empty, intSize - + ImGui.GetStyle().ScrollbarSize / 2, ImGui.GetTextLineHeightWithSpacing(), ImGuiComboFlags.NoArrowButton)) - { - dyeTable[rowIdx].Template = _stainService.LegacyTemplateCombo.CurrentSelection; - ret = true; - } - - ImGuiUtil.HoverTooltip("Dye Template", ImGuiHoveredFlags.AllowWhenDisabled); - - ImGui.TableNextColumn(); - ret |= DrawLegacyDyePreview(rowIdx, disabled, dye, floatSize); + ImGui.SetNextItemWidth(scalarSize); + CtDragHalf("##dyePreviewShininess"u8, "Dye Preview for Gloss"u8, dyePack?.Shininess, "%.1f"u8); } return ret; } - private bool DrawLegacyDyePreview(int rowIdx, bool disabled, TDyeRow dye, float floatSize) + private bool DrawLegacyDye(IColorDyeTable dyeTable, LegacyDyePack? dyePack, int rowIdx) where TDyeRow : unmanaged, ILegacyColorDyeRow { - var stain = _stainService.StainCombo1.CurrentSelection.Key; - if (stain == 0 || !_stainService.LegacyStmFile.TryGetValue(dye.Template, stain, out var values)) - return false; + var scalarSize = ColorTableScalarSize * UiHelpers.Scale; + var applyButtonWidth = ImUtf8.CalcTextSize("Apply Preview Dye"u8).X + ImGui.GetStyle().FramePadding.X * 2.0f; + var subColWidth = CalculateSubColumnWidth(2, applyButtonWidth); - using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemSpacing / 2); + var ret = false; + ref var dye = ref dyeTable[rowIdx]; - var ret = ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.PaintBrush.ToIconString(), new Vector2(ImGui.GetFrameHeight()), - "Apply the selected dye to this row.", disabled, true); + ImGui.SetNextItemWidth(scalarSize); + if (dyeTable is ColorDyeTable rwDyeTable) + { + ret |= CtDragScalar("Dye Channel"u8, default, dye.Channel + 1, "%d"u8, 1, StainService.ChannelCount, 0.1f, + value => rwDyeTable[rowIdx].Channel = (byte)(Math.Clamp(value, 1, StainService.ChannelCount) - 1)); + } + else + CtDragScalar("Dye Channel"u8, default, dye.Channel + 1, "%d"u8); + ImGui.SameLine(subColWidth); + ImGui.SetNextItemWidth(scalarSize); + if (_stainService.LegacyTemplateCombo.Draw("##dyeTemplate", dye.Template.ToString(), string.Empty, + scalarSize + ImGui.GetStyle().ScrollbarSize / 2, ImGui.GetTextLineHeightWithSpacing(), ImGuiComboFlags.NoArrowButton)) + { + dye.Template = _stainService.LegacyTemplateCombo.CurrentSelection; + ret = true; + } - ret = ret && Mtrl.ApplyDyeToRow(_stainService.LegacyStmFile, [stain], rowIdx); - - ImGui.SameLine(); - DrawLegacyDyePreview(values, floatSize); - - return ret; - } - - private bool DrawLegacyDyePreview(int rowIdx, bool disabled, ColorDyeTableRow dye, float floatSize) - { - var stain = _stainService.GetStainCombo(dye.Channel).CurrentSelection.Key; - if (stain == 0 || !_stainService.LegacyStmFile.TryGetValue(dye.Template, stain, out var values)) - return false; - - using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemSpacing / 2); - - var ret = ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.PaintBrush.ToIconString(), new Vector2(ImGui.GetFrameHeight()), - "Apply the selected dye to this row.", disabled, true); - - ret = ret - && Mtrl.ApplyDyeToRow(_stainService.LegacyStmFile, [ + ImUtf8.SameLineInner(); + ImUtf8.Text("Dye Template"u8); + ImGui.SameLine(ImGui.GetContentRegionAvail().X - applyButtonWidth + ImGui.GetStyle().ItemSpacing.X); + using var dis = ImRaii.Disabled(!dyePack.HasValue); + if (ImUtf8.Button("Apply Preview Dye"u8)) + ret |= Mtrl.ApplyDyeToRow(_stainService.LegacyStmFile, [ _stainService.StainCombo1.CurrentSelection.Key, _stainService.StainCombo2.CurrentSelection.Key, ], rowIdx); - ImGui.SameLine(); - DrawLegacyDyePreview(values, floatSize); - return ret; } - - private static void DrawLegacyDyePreview(LegacyDyePack values, float floatSize) - { - CtColorPicker("##diffusePreview"u8, default, values.DiffuseColor, "D"u8); - ImUtf8.SameLineInner(); - CtColorPicker("##specularPreview"u8, default, values.SpecularColor, "S"u8); - ImUtf8.SameLineInner(); - CtColorPicker("##emissivePreview"u8, default, values.EmissiveColor, "E"u8); - ImUtf8.SameLineInner(); - using var dis = ImRaii.Disabled(); - ImGui.SetNextItemWidth(floatSize); - var shininess = (float)values.Shininess; - ImGui.DragFloat("##shininessPreview", ref shininess, 0, shininess, shininess, "%.1f G"); - ImUtf8.SameLineInner(); - ImGui.SetNextItemWidth(floatSize); - var specularMask = (float)values.SpecularMask * 100.0f; - ImGui.DragFloat("##specularMaskPreview", ref specularMask, 0, specularMask, specularMask, "%.0f%% S"); - } }