diff --git a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ColorTable.cs b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ColorTable.cs index dc87ec41..352681bb 100644 --- a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ColorTable.cs +++ b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ColorTable.cs @@ -13,7 +13,7 @@ public partial class MtrlTab { private const float ColorTableScalarSize = 65.0f; - private int _colorTableSelectedPair = 0; + private int _colorTableSelectedPair; private bool DrawColorTable(ColorTable table, ColorDyeTable? dyeTable, bool disabled) { @@ -23,25 +23,27 @@ public partial class MtrlTab private void DrawColorTablePairSelector(ColorTable table, bool disabled) { + var style = ImGui.GetStyle(); + var itemSpacing = style.ItemSpacing.X; + var itemInnerSpacing = style.ItemInnerSpacing.X; + var framePadding = style.FramePadding; + var buttonWidth = (ImGui.GetContentRegionAvail().X - itemSpacing * 7.0f) * 0.125f; + var frameHeight = ImGui.GetFrameHeight(); + var highlighterSize = ImUtf8.CalcIconSize(FontAwesomeIcon.Crosshairs) + framePadding * 2.0f; + var spaceWidth = ImUtf8.CalcTextSize(" "u8).X; + var spacePadding = (int)MathF.Ceiling((highlighterSize.X + framePadding.X + itemInnerSpacing) / spaceWidth); + using var font = ImRaii.PushFont(UiBuilder.MonoFont); using var alignment = ImRaii.PushStyle(ImGuiStyleVar.ButtonTextAlign, new Vector2(0, 0.5f)); - var style = ImGui.GetStyle(); - var itemSpacing = style.ItemSpacing.X; - var itemInnerSpacing = style.ItemInnerSpacing.X; - var framePadding = style.FramePadding; - var buttonWidth = (ImGui.GetContentRegionAvail().X - itemSpacing * 7.0f) * 0.125f; - var frameHeight = ImGui.GetFrameHeight(); - var highlighterSize = ImUtf8.CalcIconSize(FontAwesomeIcon.Crosshairs) + framePadding * 2.0f; - var spaceWidth = ImUtf8.CalcTextSize(" "u8).X; - var spacePadding = (int)MathF.Ceiling((highlighterSize.X + framePadding.X + itemInnerSpacing) / spaceWidth); for (var i = 0; i < ColorTable.NumRows >> 1; i += 8) { for (var j = 0; j < 8; ++j) { var pairIndex = i + j; - using (var color = ImRaii.PushColor(ImGuiCol.Button, ImGui.GetColorU32(ImGuiCol.ButtonActive), pairIndex == _colorTableSelectedPair)) + using (ImRaii.PushColor(ImGuiCol.Button, ImGui.GetColorU32(ImGuiCol.ButtonActive), pairIndex == _colorTableSelectedPair)) { - if (ImUtf8.Button($"#{pairIndex + 1}".PadLeft(3 + spacePadding), new Vector2(buttonWidth, ImGui.GetFrameHeightWithSpacing() + frameHeight))) + if (ImUtf8.Button($"#{pairIndex + 1}".PadLeft(3 + spacePadding), + new Vector2(buttonWidth, ImGui.GetFrameHeightWithSpacing() + frameHeight))) _colorTableSelectedPair = pairIndex; } @@ -79,12 +81,10 @@ public partial class MtrlTab private bool DrawColorTablePairEditor(ColorTable table, ColorDyeTable? dyeTable, bool disabled) { - var retA = false; - var retB = false; - ref var rowA = ref table[_colorTableSelectedPair << 1]; - ref var rowB = ref table[(_colorTableSelectedPair << 1) | 1]; - var dyeA = dyeTable != null ? dyeTable[_colorTableSelectedPair << 1] : default; - var dyeB = dyeTable != null ? dyeTable[(_colorTableSelectedPair << 1) | 1] : default; + var retA = false; + var retB = false; + var dyeA = dyeTable?[_colorTableSelectedPair << 1] ?? default; + var dyeB = dyeTable?[(_colorTableSelectedPair << 1) | 1] ?? default; var previewDyeA = _stainService.GetStainCombo(dyeA.Channel).CurrentSelection.Key; var previewDyeB = _stainService.GetStainCombo(dyeB.Channel).CurrentSelection.Key; var dyePackA = _stainService.GudStmFile.GetValueOrNull(dyeA.Template, previewDyeA); @@ -108,68 +108,96 @@ public partial class MtrlTab using (var columns = ImUtf8.Columns(2, "ColorTable"u8)) { using var dis = ImRaii.Disabled(disabled); - using (var id = ImUtf8.PushId("ColorsA"u8)) + using (ImUtf8.PushId("ColorsA"u8)) + { retA |= DrawColors(table, dyeTable, dyePackA, _colorTableSelectedPair << 1); + } + columns.Next(); - using (var id = ImUtf8.PushId("ColorsB"u8)) + using (ImUtf8.PushId("ColorsB"u8)) + { retB |= DrawColors(table, dyeTable, dyePackB, (_colorTableSelectedPair << 1) | 1); + } } DrawHeader(" Physical Parameters"u8); using (var columns = ImUtf8.Columns(2, "ColorTable"u8)) { using var dis = ImRaii.Disabled(disabled); - using (var id = ImUtf8.PushId("PbrA"u8)) + using (ImUtf8.PushId("PbrA"u8)) + { retA |= DrawPbr(table, dyeTable, dyePackA, _colorTableSelectedPair << 1); + } + columns.Next(); - using (var id = ImUtf8.PushId("PbrB"u8)) + using (ImUtf8.PushId("PbrB"u8)) + { retB |= DrawPbr(table, dyeTable, dyePackB, (_colorTableSelectedPair << 1) | 1); + } } DrawHeader(" Sheen Layer Parameters"u8); using (var columns = ImUtf8.Columns(2, "ColorTable"u8)) { using var dis = ImRaii.Disabled(disabled); - using (var id = ImUtf8.PushId("SheenA"u8)) + using (ImUtf8.PushId("SheenA"u8)) + { retA |= DrawSheen(table, dyeTable, dyePackA, _colorTableSelectedPair << 1); + } + columns.Next(); - using (var id = ImUtf8.PushId("SheenB"u8)) + using (ImUtf8.PushId("SheenB"u8)) + { retB |= DrawSheen(table, dyeTable, dyePackB, (_colorTableSelectedPair << 1) | 1); + } } DrawHeader(" Pair Blending"u8); using (var columns = ImUtf8.Columns(2, "ColorTable"u8)) { using var dis = ImRaii.Disabled(disabled); - using (var id = ImUtf8.PushId("BlendingA"u8)) + using (ImUtf8.PushId("BlendingA"u8)) + { retA |= DrawBlending(table, dyeTable, dyePackA, _colorTableSelectedPair << 1); + } + columns.Next(); - using (var id = ImUtf8.PushId("BlendingB"u8)) + using (ImUtf8.PushId("BlendingB"u8)) + { retB |= DrawBlending(table, dyeTable, dyePackB, (_colorTableSelectedPair << 1) | 1); + } } DrawHeader(" Material Template"u8); using (var columns = ImUtf8.Columns(2, "ColorTable"u8)) { using var dis = ImRaii.Disabled(disabled); - using (var id = ImUtf8.PushId("TemplateA"u8)) + using (ImUtf8.PushId("TemplateA"u8)) + { retA |= DrawTemplate(table, dyeTable, dyePackA, _colorTableSelectedPair << 1); + } + columns.Next(); - using (var id = ImUtf8.PushId("TemplateB"u8)) + using (ImUtf8.PushId("TemplateB"u8)) + { retB |= DrawTemplate(table, dyeTable, dyePackB, (_colorTableSelectedPair << 1) | 1); + } } if (dyeTable != null) { DrawHeader(" Dye Properties"u8); - using (var columns = ImUtf8.Columns(2, "ColorTable"u8)) + using var columns = ImUtf8.Columns(2, "ColorTable"u8); + using var dis = ImRaii.Disabled(disabled); + using (ImUtf8.PushId("DyeA"u8)) { - using var dis = ImRaii.Disabled(disabled); - using (var id = ImUtf8.PushId("DyeA"u8)) - retA |= DrawDye(dyeTable, dyePackA, _colorTableSelectedPair << 1); - columns.Next(); - using (var id = ImUtf8.PushId("DyeB"u8)) - retB |= DrawDye(dyeTable, dyePackB, (_colorTableSelectedPair << 1) | 1); + retA |= DrawDye(dyeTable, dyePackA, _colorTableSelectedPair << 1); + } + + columns.Next(); + using (ImUtf8.PushId("DyeB"u8)) + { + retB |= DrawDye(dyeTable, dyePackB, (_colorTableSelectedPair << 1) | 1); } } @@ -177,11 +205,16 @@ public partial class MtrlTab using (var columns = ImUtf8.Columns(2, "ColorTable"u8)) { using var dis = ImRaii.Disabled(disabled); - using (var id = ImUtf8.PushId("FurtherA"u8)) + using (ImUtf8.PushId("FurtherA"u8)) + { retA |= DrawFurther(table, dyeTable, dyePackA, _colorTableSelectedPair << 1); + } + columns.Next(); - using (var id = ImUtf8.PushId("FurtherB"u8)) + using (ImUtf8.PushId("FurtherB"u8)) + { retB |= DrawFurther(table, dyeTable, dyePackB, (_colorTableSelectedPair << 1) | 1); + } } if (retA) @@ -195,18 +228,21 @@ public partial class MtrlTab /// Padding styles do not seem to apply to this component. It is recommended to prepend two spaces. private static void DrawHeader(ReadOnlySpan label) { - var headerColor = ImGui.GetColorU32(ImGuiCol.Header); - using var _ = ImRaii.PushColor(ImGuiCol.HeaderHovered, headerColor).Push(ImGuiCol.HeaderActive, headerColor); + var headerColor = ImGui.GetColorU32(ImGuiCol.Header); + using var _ = ImRaii.PushColor(ImGuiCol.HeaderHovered, headerColor).Push(ImGuiCol.HeaderActive, headerColor); ImUtf8.CollapsingHeader(label, ImGuiTreeNodeFlags.Leaf); } private static bool DrawColors(ColorTable table, ColorDyeTable? dyeTable, DyePack? dyePack, int rowIdx) { - var dyeOffset = ImGui.GetContentRegionAvail().X + ImGui.GetStyle().ItemSpacing.X - ImGui.GetStyle().ItemInnerSpacing.X - ImGui.GetFrameHeight() * 2.0f; + var dyeOffset = ImGui.GetContentRegionAvail().X + + ImGui.GetStyle().ItemSpacing.X + - ImGui.GetStyle().ItemInnerSpacing.X + - ImGui.GetFrameHeight() * 2.0f; - var ret = false; + var ret = false; ref var row = ref table[rowIdx]; - var dye = dyeTable != null ? dyeTable[rowIdx] : default; + var dye = dyeTable?[rowIdx] ?? default; ret |= CtColorPicker("Diffuse Color"u8, default, row.DiffuseColor, c => table[rowIdx].DiffuseColor = c); @@ -247,13 +283,17 @@ public partial class MtrlTab private static bool DrawBlending(ColorTable table, ColorDyeTable? dyeTable, DyePack? dyePack, int rowIdx) { var scalarSize = ColorTableScalarSize * UiHelpers.Scale; - var dyeOffset = ImGui.GetContentRegionAvail().X + ImGui.GetStyle().ItemSpacing.X - ImGui.GetStyle().ItemInnerSpacing.X - ImGui.GetFrameHeight() - scalarSize; + var dyeOffset = ImGui.GetContentRegionAvail().X + + ImGui.GetStyle().ItemSpacing.X + - ImGui.GetStyle().ItemInnerSpacing.X + - ImGui.GetFrameHeight() + - scalarSize; var isRowB = (rowIdx & 1) != 0; - var ret = false; + var ret = false; ref var row = ref table[rowIdx]; - var dye = dyeTable != null ? dyeTable[rowIdx] : default; + var dye = dyeTable?[rowIdx] ?? default; ImGui.SetNextItemWidth(scalarSize); ret |= CtDragHalf(isRowB ? "Field #19"u8 : "Anisotropy Degree"u8, default, row.Anisotropy, "%.2f"u8, 0.0f, HalfMaxValue, 0.1f, @@ -261,11 +301,13 @@ public partial class MtrlTab if (dyeTable != null) { ImGui.SameLine(dyeOffset); - ret |= CtApplyStainCheckbox("##dyeAnisotropy"u8, isRowB ? "Apply Field #19 on Dye"u8 : "Apply Anisotropy Degree on Dye"u8, dye.Anisotropy, + ret |= CtApplyStainCheckbox("##dyeAnisotropy"u8, isRowB ? "Apply Field #19 on Dye"u8 : "Apply Anisotropy Degree on Dye"u8, + dye.Anisotropy, b => dyeTable[rowIdx].Anisotropy = b); ImUtf8.SameLineInner(); ImGui.SetNextItemWidth(scalarSize); - CtDragHalf("##dyePreviewAnisotropy"u8, isRowB ? "Dye Preview for Field #19"u8 : "Dye Preview for Anisotropy Degree"u8, dyePack?.Anisotropy, "%.2f"u8); + CtDragHalf("##dyePreviewAnisotropy"u8, isRowB ? "Dye Preview for Field #19"u8 : "Dye Preview for Anisotropy Degree"u8, + dyePack?.Anisotropy, "%.2f"u8); } return ret; @@ -276,11 +318,11 @@ public partial class MtrlTab var scalarSize = ColorTableScalarSize * UiHelpers.Scale; var itemSpacing = ImGui.GetStyle().ItemSpacing.X; var dyeOffset = ImGui.GetContentRegionAvail().X - ImGui.GetStyle().ItemInnerSpacing.X - ImGui.GetFrameHeight() - scalarSize - 64.0f; - var subcolWidth = CalculateSubcolumnWidth(2); + var subColWidth = CalculateSubColumnWidth(2); - var ret = false; + var ret = false; ref var row = ref table[rowIdx]; - var dye = dyeTable != null ? dyeTable[rowIdx] : default; + var dye = dyeTable?[rowIdx] ?? default; ImGui.SetNextItemWidth(scalarSize); ret |= CtDragScalar("Shader ID"u8, default, row.ShaderId, "%d"u8, (ushort)0, (ushort)255, 0.25f, @@ -306,13 +348,15 @@ public partial class MtrlTab ImGui.SetCursorScreenPos(ImGui.GetCursorScreenPos() with { Y = cursor.Y }); ImGui.SetNextItemWidth(scalarSize + itemSpacing + 64.0f); using var dis = ImRaii.Disabled(); - CtSphereMapIndexPicker("###SphereMapIndexDye"u8, "Dye Preview for Sphere Map"u8, dyePack?.SphereMapIndex ?? ushort.MaxValue, false, Nop); + CtSphereMapIndexPicker("###SphereMapIndexDye"u8, "Dye Preview for Sphere Map"u8, dyePack?.SphereMapIndex ?? ushort.MaxValue, false, + Nop); } ImGui.Dummy(new Vector2(64.0f, 0.0f)); ImGui.SameLine(); ImGui.SetNextItemWidth(scalarSize); - ret |= CtDragScalar("Sphere Map Intensity"u8, default, (float)row.SphereMapMask * 100.0f, "%.0f%%"u8, HalfMinValue * 100.0f, HalfMaxValue * 100.0f, 1.0f, + ret |= CtDragScalar("Sphere Map Intensity"u8, default, (float)row.SphereMapMask * 100.0f, "%.0f%%"u8, HalfMinValue * 100.0f, + HalfMaxValue * 100.0f, 1.0f, v => table[rowIdx].SphereMapMask = (Half)(v * 0.01f)); if (dyeTable != null) { @@ -326,10 +370,10 @@ public partial class MtrlTab ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2)); - var leftLineHeight = 64.0f + ImGui.GetStyle().FramePadding.Y * 2.0f; + var leftLineHeight = 64.0f + ImGui.GetStyle().FramePadding.Y * 2.0f; var rightLineHeight = 3.0f * ImGui.GetFrameHeight() + 2.0f * ImGui.GetStyle().ItemSpacing.Y; - var lineHeight = Math.Max(leftLineHeight, rightLineHeight); - var cursorPos = ImGui.GetCursorScreenPos(); + var lineHeight = Math.Max(leftLineHeight, rightLineHeight); + var cursorPos = ImGui.GetCursorScreenPos(); ImGui.SetCursorScreenPos(cursorPos + new Vector2(0.0f, (lineHeight - leftLineHeight) * 0.5f)); ImGui.SetNextItemWidth(scalarSize + (itemSpacing + 64.0f) * 2.0f); ret |= CtTileIndexPicker("###TileIndex"u8, default, row.TileIndex, false, @@ -337,9 +381,10 @@ public partial class MtrlTab ImUtf8.SameLineInner(); ImUtf8.Text("Tile"u8); - ImGui.SameLine(subcolWidth); - ImGui.SetCursorScreenPos(ImGui.GetCursorScreenPos() with { Y = cursorPos.Y + (lineHeight - rightLineHeight) * 0.5f, }); - using (var cld = ImUtf8.Child("###TileProperties"u8, new(ImGui.GetContentRegionAvail().X, float.Lerp(rightLineHeight, lineHeight, 0.5f)), false)) + ImGui.SameLine(subColWidth); + ImGui.SetCursorScreenPos(ImGui.GetCursorScreenPos() with { Y = cursorPos.Y + (lineHeight - rightLineHeight) * 0.5f }); + using (ImUtf8.Child("###TileProperties"u8, + new Vector2(ImGui.GetContentRegionAvail().X, float.Lerp(rightLineHeight, lineHeight, 0.5f)))) { ImGui.Dummy(new Vector2(scalarSize, 0.0f)); ImUtf8.SameLineInner(); @@ -350,7 +395,8 @@ public partial class MtrlTab ret |= CtTileTransformMatrix(row.TileTransform, scalarSize, true, m => table[rowIdx].TileTransform = m); ImUtf8.SameLineInner(); - ImGui.SetCursorScreenPos(ImGui.GetCursorScreenPos() - new Vector2(0.0f, (ImGui.GetFrameHeight() + ImGui.GetStyle().ItemSpacing.Y) * 0.5f)); + ImGui.SetCursorScreenPos(ImGui.GetCursorScreenPos() + - new Vector2(0.0f, (ImGui.GetFrameHeight() + ImGui.GetStyle().ItemSpacing.Y) * 0.5f)); ImUtf8.Text("Tile Transform"u8); } @@ -360,15 +406,20 @@ public partial class MtrlTab private static bool DrawPbr(ColorTable table, ColorDyeTable? dyeTable, DyePack? dyePack, int rowIdx) { 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; + var subColWidth = CalculateSubColumnWidth(2) + ImGui.GetStyle().ItemSpacing.X; + var dyeOffset = subColWidth + - ImGui.GetStyle().ItemSpacing.X * 2.0f + - ImGui.GetStyle().ItemInnerSpacing.X + - ImGui.GetFrameHeight() + - scalarSize; - var ret = false; + var ret = false; ref var row = ref table[rowIdx]; - var dye = dyeTable != null ? dyeTable[rowIdx] : default; + var dye = dyeTable?[rowIdx] ?? default; ImGui.SetNextItemWidth(scalarSize); - ret |= CtDragScalar("Roughness"u8, default, (float)row.Roughness * 100.0f, "%.0f%%"u8, HalfMinValue * 100.0f, HalfMaxValue * 100.0f, 1.0f, + ret |= CtDragScalar("Roughness"u8, default, (float)row.Roughness * 100.0f, "%.0f%%"u8, HalfMinValue * 100.0f, HalfMaxValue * 100.0f, + 1.0f, v => table[rowIdx].Roughness = (Half)(v * 0.01f)); if (dyeTable != null) { @@ -380,13 +431,14 @@ public partial class MtrlTab CtDragScalar("##dyePreviewRoughness"u8, "Dye Preview for Roughness"u8, (float?)dyePack?.Roughness * 100.0f, "%.0f%%"u8); } - ImGui.SameLine(subcolWidth); + ImGui.SameLine(subColWidth); ImGui.SetNextItemWidth(scalarSize); - ret |= CtDragScalar("Metalness"u8, default, (float)row.Metalness * 100.0f, "%.0f%%"u8, HalfMinValue * 100.0f, HalfMaxValue * 100.0f, 1.0f, + ret |= CtDragScalar("Metalness"u8, default, (float)row.Metalness * 100.0f, "%.0f%%"u8, HalfMinValue * 100.0f, HalfMaxValue * 100.0f, + 1.0f, v => table[rowIdx].Metalness = (Half)(v * 0.01f)); if (dyeTable != null) { - ImGui.SameLine(subcolWidth + dyeOffset); + ImGui.SameLine(subColWidth + dyeOffset); ret |= CtApplyStainCheckbox("##dyeMetalness"u8, "Apply Metalness on Dye"u8, dye.Metalness, b => dyeTable[rowIdx].Metalness = b); ImUtf8.SameLineInner(); @@ -400,12 +452,16 @@ public partial class MtrlTab private static bool DrawSheen(ColorTable table, ColorDyeTable? dyeTable, DyePack? dyePack, int rowIdx) { 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; + var subColWidth = CalculateSubColumnWidth(2) + ImGui.GetStyle().ItemSpacing.X; + var dyeOffset = subColWidth + - ImGui.GetStyle().ItemSpacing.X * 2.0f + - ImGui.GetStyle().ItemInnerSpacing.X + - ImGui.GetFrameHeight() + - scalarSize; - var ret = false; + var ret = false; ref var row = ref table[rowIdx]; - var dye = dyeTable != null ? dyeTable[rowIdx] : default; + var dye = dyeTable?[rowIdx] ?? default; ImGui.SetNextItemWidth(scalarSize); ret |= CtDragScalar("Sheen"u8, default, (float)row.SheenRate * 100.0f, "%.0f%%"u8, HalfMinValue * 100.0f, HalfMaxValue * 100.0f, 1.0f, @@ -420,13 +476,14 @@ public partial class MtrlTab CtDragScalar("##dyePreviewSheenRate"u8, "Dye Preview for Sheen"u8, (float?)dyePack?.SheenRate * 100.0f, "%.0f%%"u8); } - ImGui.SameLine(subcolWidth); + ImGui.SameLine(subColWidth); ImGui.SetNextItemWidth(scalarSize); - ret |= CtDragScalar("Sheen Tint"u8, default, (float)row.SheenTintRate * 100.0f, "%.0f%%"u8, HalfMinValue * 100.0f, HalfMaxValue * 100.0f, 1.0f, + ret |= CtDragScalar("Sheen Tint"u8, default, (float)row.SheenTintRate * 100.0f, "%.0f%%"u8, HalfMinValue * 100.0f, + HalfMaxValue * 100.0f, 1.0f, v => table[rowIdx].SheenTintRate = (Half)(v * 0.01f)); if (dyeTable != null) { - ImGui.SameLine(subcolWidth + dyeOffset); + ImGui.SameLine(subColWidth + dyeOffset); ret |= CtApplyStainCheckbox("##dyeSheenTintRate"u8, "Apply Sheen Tint on Dye"u8, dye.SheenTintRate, b => dyeTable[rowIdx].SheenTintRate = b); ImUtf8.SameLineInner(); @@ -435,7 +492,8 @@ public partial class MtrlTab } ImGui.SetNextItemWidth(scalarSize); - ret |= CtDragScalar("Sheen Roughness"u8, default, 100.0f / (float)row.SheenAperture, "%.0f%%"u8, 100.0f / HalfMaxValue, 100.0f / HalfEpsilon, 1.0f, + ret |= CtDragScalar("Sheen Roughness"u8, default, 100.0f / (float)row.SheenAperture, "%.0f%%"u8, 100.0f / HalfMaxValue, + 100.0f / HalfEpsilon, 1.0f, v => table[rowIdx].SheenAperture = (Half)(100.0f / v)); if (dyeTable != null) { @@ -444,7 +502,8 @@ public partial class MtrlTab b => dyeTable[rowIdx].SheenAperture = b); ImUtf8.SameLineInner(); ImGui.SetNextItemWidth(scalarSize); - CtDragScalar("##dyePreviewSheenRoughness"u8, "Dye Preview for Sheen Roughness"u8, 100.0f / (float?)dyePack?.SheenAperture, "%.0f%%"u8); + CtDragScalar("##dyePreviewSheenRoughness"u8, "Dye Preview for Sheen Roughness"u8, 100.0f / (float?)dyePack?.SheenAperture, + "%.0f%%"u8); } return ret; @@ -453,12 +512,16 @@ public partial class MtrlTab private static bool DrawFurther(ColorTable table, ColorDyeTable? dyeTable, DyePack? dyePack, int rowIdx) { 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; + var subColWidth = CalculateSubColumnWidth(2) + ImGui.GetStyle().ItemSpacing.X; + var dyeOffset = subColWidth + - ImGui.GetStyle().ItemSpacing.X * 2.0f + - ImGui.GetStyle().ItemInnerSpacing.X + - ImGui.GetFrameHeight() + - scalarSize; - var ret = false; + var ret = false; ref var row = ref table[rowIdx]; - var dye = dyeTable != null ? dyeTable[rowIdx] : default; + var dye = dyeTable?[rowIdx] ?? default; ImGui.SetNextItemWidth(scalarSize); ret |= CtDragHalf("Field #11"u8, default, row.Scalar11, "%.2f"u8, HalfMinValue, HalfMaxValue, 0.1f, @@ -479,7 +542,7 @@ public partial class MtrlTab ret |= CtDragHalf("Field #3"u8, default, row.Scalar3, "%.2f"u8, HalfMinValue, HalfMaxValue, 0.1f, v => table[rowIdx].Scalar3 = v); - ImGui.SameLine(subcolWidth); + ImGui.SameLine(subColWidth); ImGui.SetNextItemWidth(scalarSize); ret |= CtDragHalf("Field #7"u8, default, row.Scalar7, "%.2f"u8, HalfMinValue, HalfMaxValue, 0.1f, v => table[rowIdx].Scalar7 = v); @@ -488,7 +551,7 @@ public partial class MtrlTab ret |= CtDragHalf("Field #15"u8, default, row.Scalar15, "%.2f"u8, HalfMinValue, HalfMaxValue, 0.1f, v => table[rowIdx].Scalar15 = v); - ImGui.SameLine(subcolWidth); + ImGui.SameLine(subColWidth); ImGui.SetNextItemWidth(scalarSize); ret |= CtDragHalf("Field #17"u8, default, row.Scalar17, "%.2f"u8, HalfMinValue, HalfMaxValue, 0.1f, v => table[rowIdx].Scalar17 = v); @@ -497,7 +560,7 @@ public partial class MtrlTab ret |= CtDragHalf("Field #20"u8, default, row.Scalar20, "%.2f"u8, HalfMinValue, HalfMaxValue, 0.1f, v => table[rowIdx].Scalar20 = v); - ImGui.SameLine(subcolWidth); + ImGui.SameLine(subColWidth); ImGui.SetNextItemWidth(scalarSize); ret |= CtDragHalf("Field #22"u8, default, row.Scalar22, "%.2f"u8, HalfMinValue, HalfMaxValue, 0.1f, v => table[rowIdx].Scalar22 = v); @@ -513,33 +576,32 @@ public partial class MtrlTab { 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); - - var ret = false; + var subColWidth = CalculateSubColumnWidth(2, applyButtonWidth); + + var ret = false; ref var dye = ref dyeTable[rowIdx]; ImGui.SetNextItemWidth(scalarSize); ret |= CtDragScalar("Dye Channel"u8, default, dye.Channel + 1, "%d"u8, 1, StainService.ChannelCount, 0.1f, value => dyeTable[rowIdx].Channel = (byte)(Math.Clamp(value, 1, StainService.ChannelCount) - 1)); - ImGui.SameLine(subcolWidth); + ImGui.SameLine(subColWidth); ImGui.SetNextItemWidth(scalarSize); if (_stainService.GudTemplateCombo.Draw("##dyeTemplate", dye.Template.ToString(), string.Empty, - scalarSize + ImGui.GetStyle().ScrollbarSize / 2, ImGui.GetTextLineHeightWithSpacing(), ImGuiComboFlags.NoArrowButton)) + scalarSize + ImGui.GetStyle().ScrollbarSize / 2, ImGui.GetTextLineHeightWithSpacing(), ImGuiComboFlags.NoArrowButton)) { dye.Template = _stainService.LegacyTemplateCombo.CurrentSelection; ret = true; } + 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.GudStmFile, [ _stainService.StainCombo1.CurrentSelection.Key, _stainService.StainCombo2.CurrentSelection.Key, ], rowIdx); - } return ret; } @@ -554,9 +616,9 @@ public partial class MtrlTab ImGui.TextUnformatted(text); } - private static float CalculateSubcolumnWidth(int numSubcolumns, float reservedSpace = 0.0f) + private static float CalculateSubColumnWidth(int numSubColumns, float reservedSpace = 0.0f) { var itemSpacing = ImGui.GetStyle().ItemSpacing.X; - return (ImGui.GetContentRegionAvail().X - reservedSpace - itemSpacing * (numSubcolumns - 1)) / numSubcolumns + itemSpacing; + return (ImGui.GetContentRegionAvail().X - reservedSpace - itemSpacing * (numSubColumns - 1)) / numSubColumns + itemSpacing; } } diff --git a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.CommonColorTable.cs b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.CommonColorTable.cs index 2b093e23..09c8ea61 100644 --- a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.CommonColorTable.cs +++ b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.CommonColorTable.cs @@ -12,9 +12,9 @@ namespace Penumbra.UI.AdvancedWindow.Materials; public partial class MtrlTab { - private static readonly float HalfMinValue = (float)Half.MinValue; - private static readonly float HalfMaxValue = (float)Half.MaxValue; - private static readonly float HalfEpsilon = (float)Half.Epsilon; + private static readonly float HalfMinValue = (float)Half.MinValue; + private static readonly float HalfMaxValue = (float)Half.MaxValue; + private static readonly float HalfEpsilon = (float)Half.Epsilon; private static readonly FontAwesomeCheckbox ApplyStainCheckbox = new(FontAwesomeIcon.FillDrip); @@ -22,11 +22,11 @@ public partial class MtrlTab private bool DrawColorTableSection(bool disabled) { - if ((!ShpkLoading && !SamplerIds.Contains(ShpkFile.TableSamplerId)) || Mtrl.Table == null) + if (!_shpkLoading && !SamplerIds.Contains(ShpkFile.TableSamplerId) || Mtrl.Table == null) return false; ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2)); - if (!ImGui.CollapsingHeader("Color Table", ImGuiTreeNodeFlags.DefaultOpen)) + if (!ImUtf8.CollapsingHeader("Color Table"u8, ImGuiTreeNodeFlags.DefaultOpen)) return false; ColorTableCopyAllClipboardButton(); @@ -35,7 +35,7 @@ public partial class MtrlTab if (!disabled) { ImGui.SameLine(); - ImGui.Dummy(ImGuiHelpers.ScaledVector2(20, 0)); + ImUtf8.IconDummy(); ImGui.SameLine(); ret |= ColorTableDyeableCheckbox(); } @@ -43,17 +43,18 @@ public partial class MtrlTab if (Mtrl.DyeTable != null) { ImGui.SameLine(); - ImGui.Dummy(ImGuiHelpers.ScaledVector2(20, 0)); + ImUtf8.IconDummy(); ImGui.SameLine(); ret |= DrawPreviewDye(disabled); } ret |= Mtrl.Table switch { - LegacyColorTable legacyTable => DrawLegacyColorTable(legacyTable, Mtrl.DyeTable as LegacyColorDyeTable, disabled), - ColorTable table when Mtrl.ShaderPackage.Name is "characterlegacy.shpk" => DrawLegacyColorTable(table, Mtrl.DyeTable as ColorDyeTable, disabled), - ColorTable table => DrawColorTable(table, Mtrl.DyeTable as ColorDyeTable, disabled), - _ => false, + LegacyColorTable legacyTable => DrawLegacyColorTable(legacyTable, Mtrl.DyeTable as LegacyColorDyeTable, disabled), + ColorTable table when Mtrl.ShaderPackage.Name is "characterlegacy.shpk" => DrawLegacyColorTable(table, + Mtrl.DyeTable as ColorDyeTable, disabled), + ColorTable table => DrawColorTable(table, Mtrl.DyeTable as ColorDyeTable, disabled), + _ => false, }; return ret; @@ -64,7 +65,7 @@ public partial class MtrlTab if (Mtrl.Table == null) return; - if (!ImGui.Button("Export All Rows to Clipboard", ImGuiHelpers.ScaledVector2(200, 0))) + if (!ImUtf8.Button("Export All Rows to Clipboard"u8, ImGuiHelpers.ScaledVector2(200, 0))) return; try @@ -178,16 +179,18 @@ public partial class MtrlTab private bool ColorTableDyeableCheckbox() { var dyeable = Mtrl.DyeTable != null; - var ret = ImGui.Checkbox("Dyeable", ref dyeable); + var ret = ImUtf8.Checkbox("Dyeable"u8, ref dyeable); if (ret) { - Mtrl.DyeTable = dyeable ? Mtrl.Table switch - { - ColorTable => new ColorDyeTable(), - LegacyColorTable => new LegacyColorDyeTable(), - _ => null, - } : null; + Mtrl.DyeTable = dyeable + ? Mtrl.Table switch + { + ColorTable => new ColorDyeTable(), + LegacyColorTable => new LegacyColorDyeTable(), + _ => null, + } + : null; UpdateColorTablePreview(); } @@ -227,24 +230,27 @@ public partial class MtrlTab private void ColorTableHighlightButton(int pairIdx, bool disabled) { - ImUtf8.IconButton(FontAwesomeIcon.Crosshairs, "Highlight this pair of rows on your character, if possible.\n\nHighlight colors can be configured in Penumbra's settings."u8, - ImGui.GetFrameHeight() * Vector2.One, disabled || ColorTablePreviewers.Count == 0); + ImUtf8.IconButton(FontAwesomeIcon.Crosshairs, + "Highlight this pair of rows on your character, if possible.\n\nHighlight colors can be configured in Penumbra's settings."u8, + ImGui.GetFrameHeight() * Vector2.One, disabled || _colorTablePreviewers.Count == 0); if (ImGui.IsItemHovered()) HighlightColorTablePair(pairIdx); - else if (HighlightedColorTablePair == pairIdx) + else if (_highlightedColorTablePair == pairIdx) CancelColorTableHighlight(); } private static void CtBlendRect(Vector2 rcMin, Vector2 rcMax, uint topColor, uint bottomColor) { - var style = ImGui.GetStyle(); - var frameRounding = style.FrameRounding; + var style = ImGui.GetStyle(); + var frameRounding = style.FrameRounding; var frameThickness = style.FrameBorderSize; - var borderColor = ImGui.GetColorU32(ImGuiCol.Border); - var drawList = ImGui.GetWindowDrawList(); + var borderColor = ImGui.GetColorU32(ImGuiCol.Border); + var drawList = ImGui.GetWindowDrawList(); if (topColor == bottomColor) + { drawList.AddRectFilled(rcMin, rcMax, topColor, frameRounding, ImDrawFlags.RoundCornersDefault); + } else { drawList.AddRectFilled( @@ -258,10 +264,12 @@ public partial class MtrlTab rcMin with { Y = float.Lerp(rcMin.Y, rcMax.Y, 2.0f / 3) }, rcMax, bottomColor, frameRounding, ImDrawFlags.RoundCornersBottomLeft | ImDrawFlags.RoundCornersBottomRight); } + drawList.AddRect(rcMin, rcMax, borderColor, frameRounding, ImDrawFlags.RoundCornersDefault, frameThickness); } - private static bool CtColorPicker(ReadOnlySpan label, ReadOnlySpan description, HalfColor current, Action setter, ReadOnlySpan letter = default) + private static bool CtColorPicker(ReadOnlySpan label, ReadOnlySpan description, HalfColor current, Action setter, + ReadOnlySpan letter = default) { var ret = false; var inputSqrt = PseudoSqrtRgb((Vector3)current); @@ -291,10 +299,13 @@ public partial class MtrlTab return ret; } - private static void CtColorPicker(ReadOnlySpan label, ReadOnlySpan description, HalfColor? current, ReadOnlySpan letter = default) + private static void CtColorPicker(ReadOnlySpan label, ReadOnlySpan description, HalfColor? current, + ReadOnlySpan letter = default) { if (current.HasValue) + { CtColorPicker(label, description, current.Value, Nop, letter); + } else { var tmp = Vector4.Zero; @@ -308,8 +319,8 @@ public partial class MtrlTab if (letter.Length > 0 && ImGui.IsItemVisible()) { - var textSize = ImUtf8.CalcTextSize(letter); - var center = ImGui.GetItemRectMin() + (ImGui.GetItemRectSize() - textSize) / 2; + var textSize = ImUtf8.CalcTextSize(letter); + var center = ImGui.GetItemRectMin() + (ImGui.GetItemRectSize() - textSize) / 2; ImGui.GetWindowDrawList().AddText(letter, center, 0x80000000u); } @@ -319,7 +330,7 @@ public partial class MtrlTab private static bool CtApplyStainCheckbox(ReadOnlySpan label, ReadOnlySpan description, bool current, Action setter) { - var tmp = current; + var tmp = current; var result = ApplyStainCheckbox.Draw(label, ref tmp); ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, description); if (!result || tmp == current) @@ -329,68 +340,79 @@ public partial class MtrlTab return true; } - private static bool CtDragHalf(ReadOnlySpan label, ReadOnlySpan description, Half value, ReadOnlySpan format, float min, float max, float speed, Action setter) + private static bool CtDragHalf(ReadOnlySpan label, ReadOnlySpan description, Half value, ReadOnlySpan format, float min, + float max, float speed, Action setter) { - var tmp = (float)value; + var tmp = (float)value; var result = ImUtf8.DragScalar(label, ref tmp, format, min, max, speed); ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, description); if (!result) return false; + var newValue = (Half)tmp; if (newValue == value) return false; + setter(newValue); return true; } - private static bool CtDragHalf(ReadOnlySpan label, ReadOnlySpan description, ref Half value, ReadOnlySpan format, float min, float max, float speed) + private static bool CtDragHalf(ReadOnlySpan label, ReadOnlySpan description, ref Half value, ReadOnlySpan format, + float min, float max, float speed) { - var tmp = (float)value; + var tmp = (float)value; var result = ImUtf8.DragScalar(label, ref tmp, format, min, max, speed); ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, description); if (!result) return false; + var newValue = (Half)tmp; if (newValue == value) return false; + value = newValue; return true; } private static void CtDragHalf(ReadOnlySpan label, ReadOnlySpan description, Half? value, ReadOnlySpan format) { - using var _ = ImRaii.Disabled(); - var valueOrDefault = value ?? Half.Zero; - var floatValue = (float)valueOrDefault; + using var _ = ImRaii.Disabled(); + var valueOrDefault = value ?? Half.Zero; + var floatValue = (float)valueOrDefault; CtDragHalf(label, description, valueOrDefault, value.HasValue ? format : "-"u8, floatValue, floatValue, 0.0f, Nop); } - private static bool CtDragScalar(ReadOnlySpan label, ReadOnlySpan description, T value, ReadOnlySpan format, T min, T max, float speed, Action setter) where T : unmanaged, INumber + private static bool CtDragScalar(ReadOnlySpan label, ReadOnlySpan description, T value, ReadOnlySpan format, T min, + T max, float speed, Action setter) where T : unmanaged, INumber { - var tmp = value; + var tmp = value; var result = ImUtf8.DragScalar(label, ref tmp, format, min, max, speed); ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, description); if (!result || tmp == value) return false; + setter(tmp); return true; } - private static bool CtDragScalar(ReadOnlySpan label, ReadOnlySpan description, ref T value, ReadOnlySpan format, T min, T max, float speed) where T : unmanaged, INumber + private static bool CtDragScalar(ReadOnlySpan label, ReadOnlySpan description, ref T value, ReadOnlySpan format, T min, + T max, float speed) where T : unmanaged, INumber { - var tmp = value; + var tmp = value; var result = ImUtf8.DragScalar(label, ref tmp, format, min, max, speed); ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, description); if (!result || tmp == value) return false; + value = tmp; return true; } - private static void CtDragScalar(ReadOnlySpan label, ReadOnlySpan description, T? value, ReadOnlySpan format) where T : unmanaged, INumber + private static void CtDragScalar(ReadOnlySpan label, ReadOnlySpan description, T? value, ReadOnlySpan format) + where T : unmanaged, INumber { - using var _ = ImRaii.Disabled(); - var valueOrDefault = value ?? T.Zero; + using var _ = ImRaii.Disabled(); + var valueOrDefault = value ?? T.Zero; CtDragScalar(label, description, valueOrDefault, value.HasValue ? format : "-"u8, valueOrDefault, valueOrDefault, 0.0f, Nop); } @@ -398,14 +420,17 @@ public partial class MtrlTab { if (!_materialTemplatePickers.DrawTileIndexPicker(label, description, ref value, compact)) return false; + setter(value); return true; } - private bool CtSphereMapIndexPicker(ReadOnlySpan label, ReadOnlySpan description, ushort value, bool compact, Action setter) + private bool CtSphereMapIndexPicker(ReadOnlySpan label, ReadOnlySpan description, ushort value, bool compact, + Action setter) { if (!_materialTemplatePickers.DrawSphereMapIndexPicker(label, description, ref value, compact)) return false; + setter(value); return true; } @@ -430,33 +455,34 @@ public partial class MtrlTab ret |= CtDragHalf("##TileTransformVU"u8, "Tile Skew V"u8, ref tmp.VU, "%.2f"u8, HalfMinValue, HalfMaxValue, 0.1f); if (!ret || tmp == value) return false; + setter(tmp); } else { value.Decompose(out var scale, out var rotation, out var shear); rotation *= 180.0f / MathF.PI; - shear *= 180.0f / MathF.PI; + shear *= 180.0f / MathF.PI; ImGui.SetNextItemWidth(floatSize); var scaleXChanged = CtDragScalar("##TileScaleU"u8, "Tile Scale U"u8, ref scale.X, "%.2f"u8, HalfMinValue, HalfMaxValue, 0.1f); var activated = ImGui.IsItemActivated(); var deactivated = ImGui.IsItemDeactivated(); ImUtf8.SameLineInner(); ImGui.SetNextItemWidth(floatSize); - var scaleYChanged = CtDragScalar("##TileScaleV"u8, "Tile Scale V"u8, ref scale.Y, "%.2f"u8, HalfMinValue, HalfMaxValue, 0.1f); - activated |= ImGui.IsItemActivated(); - deactivated |= ImGui.IsItemDeactivated(); + var scaleYChanged = CtDragScalar("##TileScaleV"u8, "Tile Scale V"u8, ref scale.Y, "%.2f"u8, HalfMinValue, HalfMaxValue, 0.1f); + activated |= ImGui.IsItemActivated(); + deactivated |= ImGui.IsItemDeactivated(); if (!twoRowLayout) ImUtf8.SameLineInner(); ImGui.SetNextItemWidth(floatSize); - var rotationChanged = CtDragScalar("##TileRotation"u8, "Tile Rotation"u8, ref rotation, "%.0f°"u8, -180.0f, 180.0f, 1.0f); - activated |= ImGui.IsItemActivated(); - deactivated |= ImGui.IsItemDeactivated(); + var rotationChanged = CtDragScalar("##TileRotation"u8, "Tile Rotation"u8, ref rotation, "%.0f°"u8, -180.0f, 180.0f, 1.0f); + activated |= ImGui.IsItemActivated(); + deactivated |= ImGui.IsItemDeactivated(); ImUtf8.SameLineInner(); ImGui.SetNextItemWidth(floatSize); - var shearChanged = CtDragScalar("##TileShear"u8, "Tile Shear"u8, ref shear, "%.0f°"u8, -90.0f, 90.0f, 1.0f); - activated |= ImGui.IsItemActivated(); - deactivated |= ImGui.IsItemDeactivated(); + var shearChanged = CtDragScalar("##TileShear"u8, "Tile Shear"u8, ref shear, "%.0f°"u8, -90.0f, 90.0f, 1.0f); + activated |= ImGui.IsItemActivated(); + deactivated |= ImGui.IsItemDeactivated(); if (deactivated) _pinnedTileTransform = null; else if (activated) @@ -464,6 +490,7 @@ public partial class MtrlTab ret = scaleXChanged | scaleYChanged | rotationChanged | shearChanged; if (!ret) return false; + if (_pinnedTileTransform.HasValue) { var (pinScale, pinRotation, pinShear) = _pinnedTileTransform.Value; @@ -476,11 +503,14 @@ public partial class MtrlTab if (!shearChanged) shear = pinShear; } + var newValue = HalfMatrix2x2.Compose(scale, rotation * MathF.PI / 180.0f, shear * MathF.PI / 180.0f); if (newValue == value) return false; + setter(newValue); } + return true; } diff --git a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.Constants.cs b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.Constants.cs index 56496005..176ec3f4 100644 --- a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.Constants.cs +++ b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.Constants.cs @@ -35,7 +35,7 @@ public partial class MtrlTab Constants.Clear(); string mpPrefix; - if (AssociatedShpk == null) + if (_associatedShpk == null) { mpPrefix = MaterialParamsConstantName.Value!; var fcGroup = FindOrAddGroup(Constants, "Further Constants"); @@ -51,12 +51,12 @@ public partial class MtrlTab } else { - mpPrefix = AssociatedShpk.GetConstantById(MaterialParamsConstantId)?.Name ?? MaterialParamsConstantName.Value!; + mpPrefix = _associatedShpk.GetConstantById(MaterialParamsConstantId)?.Name ?? MaterialParamsConstantName.Value!; var autoNameMaxLength = Math.Max(Names.LongestKnownNameLength, mpPrefix.Length + 8); - foreach (var shpkConstant in AssociatedShpk.MaterialParams) + foreach (var shpkConstant in _associatedShpk.MaterialParams) { var name = Names.KnownNames.TryResolve(shpkConstant.Id); - var constant = Mtrl.GetOrAddConstant(shpkConstant.Id, AssociatedShpk, out var constantIndex); + var constant = Mtrl.GetOrAddConstant(shpkConstant.Id, _associatedShpk, out var constantIndex); var values = Mtrl.GetConstantValue(constant); var handledElements = new IndexSet(values.Length, false); @@ -64,8 +64,8 @@ public partial class MtrlTab if (dkData != null) foreach (var dkConstant in dkData) { - var offset = (int)dkConstant.EffectiveByteOffset; - var length = values.Length - offset; + var offset = (int)dkConstant.EffectiveByteOffset; + var length = values.Length - offset; var constantSize = dkConstant.EffectiveByteSize; if (constantSize.HasValue) length = Math.Min(length, (int)constantSize.Value); @@ -86,7 +86,6 @@ public partial class MtrlTab foreach (var (start, end) in handledElements.Ranges(complement: true)) { if (start == 0 && end == values.Length && end - start <= 16) - { if (name.Value != null) { fcGroup.Add(( @@ -94,7 +93,6 @@ public partial class MtrlTab constantIndex, 0..values.Length, string.Empty, true, DefaultConstantEditorFor(name))); continue; } - } if ((shpkConstant.ByteOffset & 0x3) == 0 && (shpkConstant.ByteSize & 0x3) == 0) { @@ -105,7 +103,8 @@ public partial class MtrlTab var rangeEnd = Math.Min(i + 16, end); if (rangeEnd > rangeStart) { - var autoName = $"{mpPrefix}[{j,2:D}]{VectorSwizzle(((offset + rangeStart) & 0xF) >> 2, ((offset + rangeEnd - 1) & 0xF) >> 2)}"; + var autoName = + $"{mpPrefix}[{j,2:D}]{VectorSwizzle(((offset + rangeStart) & 0xF) >> 2, ((offset + rangeEnd - 1) & 0xF) >> 2)}"; fcGroup.Add(( $"{autoName.PadRight(autoNameMaxLength)} (0x{shpkConstant.Id:X8})", constantIndex, rangeStart..rangeEnd, string.Empty, true, DefaultConstantEditorFor(name))); @@ -116,7 +115,8 @@ public partial class MtrlTab { for (var i = start; i < end; i += 16) { - fcGroup.Add(($"{"???".PadRight(autoNameMaxLength)} (0x{shpkConstant.Id:X8})", constantIndex, i..Math.Min(i + 16, end), string.Empty, true, + fcGroup.Add(($"{"???".PadRight(autoNameMaxLength)} (0x{shpkConstant.Id:X8})", constantIndex, + i..Math.Min(i + 16, end), string.Empty, true, DefaultConstantEditorFor(name))); } } @@ -178,15 +178,16 @@ public partial class MtrlTab ret = true; SetMaterialParameter(constant.Id, slice.Start, buffer[slice]); } - var shpkConstant = AssociatedShpk?.GetMaterialParamById(constant.Id); - var defaultConstantValue = shpkConstant.HasValue ? AssociatedShpk!.GetMaterialParamDefault(shpkConstant.Value) : []; + + var shpkConstant = _associatedShpk?.GetMaterialParamById(constant.Id); + var defaultConstantValue = shpkConstant.HasValue ? _associatedShpk!.GetMaterialParamDefault(shpkConstant.Value) : []; var defaultValue = IsValid(slice, defaultConstantValue.Length) ? defaultConstantValue[slice] : []; - var canReset = AssociatedShpk?.MaterialParamsDefaults != null + var canReset = _associatedShpk?.MaterialParamsDefaults != null ? defaultValue.Length > 0 && !defaultValue.SequenceEqual(buffer[slice]) : buffer[slice].ContainsAnyExcept((byte)0); ImUtf8.SameLineInner(); if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Backspace.ToIconString(), ImGui.GetFrameHeight() * Vector2.One, - "Reset this constant to its default value.\n\nHold Ctrl to unlock.", !ImGui.GetIO().KeyCtrl || !canReset, true)) + "Reset this constant to its default value.\n\nHold Ctrl to unlock.", !ImGui.GetIO().KeyCtrl || !canReset, true)) { ret = true; if (defaultValue.Length > 0) diff --git a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.Devkit.cs b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.Devkit.cs index cd62d58f..26fe3dcb 100644 --- a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.Devkit.cs +++ b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.Devkit.cs @@ -1,3 +1,4 @@ +using JetBrains.Annotations; using Newtonsoft.Json.Linq; using OtterGui.Text.Widget.Editors; using Penumbra.String.Classes; @@ -29,8 +30,8 @@ public partial class MtrlTab } private T? TryGetShpkDevkitData(string category, uint? id, bool mayVary) where T : class - => TryGetShpkDevkitData(AssociatedShpkDevkit, LoadedShpkDevkitPathName, category, id, mayVary) - ?? TryGetShpkDevkitData(AssociatedBaseDevkit, LoadedBaseDevkitPathName, category, id, mayVary); + => TryGetShpkDevkitData(_associatedShpkDevkit, _loadedShpkDevkitPathName, category, id, mayVary) + ?? TryGetShpkDevkitData(_associatedBaseDevkit, _loadedBaseDevkitPathName, category, id, mayVary); private T? TryGetShpkDevkitData(JObject? devkit, string devkitPathName, string category, uint? id, bool mayVary) where T : class { @@ -47,7 +48,7 @@ public partial class MtrlTab { var selector = BuildSelector(data!["Vary"]! .Select(key => (uint)key) - .Select(key => Mtrl.GetShaderKey(key)?.Value ?? AssociatedShpk!.GetMaterialKeyById(key)!.Value.DefaultValue)); + .Select(key => Mtrl.GetShaderKey(key)?.Value ?? _associatedShpk!.GetMaterialKeyById(key)!.Value.DefaultValue)); var index = (int)data["Selectors"]![selector.ToString()]!; data = data["Items"]![index]; } @@ -62,12 +63,14 @@ public partial class MtrlTab } } + [UsedImplicitly] private sealed class DevkitShaderKeyValue { public string Label = string.Empty; public string Description = string.Empty; } + [UsedImplicitly] private sealed class DevkitShaderKey { public string Label = string.Empty; @@ -75,6 +78,7 @@ public partial class MtrlTab public Dictionary Values = []; } + [UsedImplicitly] private sealed class DevkitSampler { public string Label = string.Empty; @@ -84,14 +88,16 @@ public partial class MtrlTab private enum DevkitConstantType { - Hidden = -1, - Float = 0, + Hidden = -1, + Float = 0, + /// Integer encoded as a float. - Integer = 1, - Color = 2, - Enum = 3, + Integer = 1, + Color = 2, + Enum = 3, + /// Native integer. - Int32 = 4, + Int32 = 4, Int32Enum = 5, Int8 = 6, Int8Enum = 7, @@ -105,6 +111,7 @@ public partial class MtrlTab SphereMapIndex = 15, } + [UsedImplicitly] private sealed class DevkitConstantValue { public string Label = string.Empty; @@ -112,6 +119,7 @@ public partial class MtrlTab public double Value = 0; } + [UsedImplicitly] private sealed class DevkitConstant { public uint Offset = 0; @@ -147,7 +155,7 @@ public partial class MtrlTab => ByteOffset ?? Offset * ValueSize; public uint? EffectiveByteSize - => ByteSize ?? (Length * ValueSize); + => ByteSize ?? Length * ValueSize; public unsafe uint ValueSize => Type switch @@ -198,19 +206,23 @@ public partial class MtrlTab private IEditor CreateIntegerEditor() where T : unmanaged, INumber => ((Drag || Slider) && !Hex - ? (Drag - ? (IEditor)DragEditor.CreateInteger(ToInteger(Minimum), ToInteger(Maximum), Speed ?? 0.25f, RelativeSpeed, Unit, 0) - : SliderEditor.CreateInteger(ToInteger(Minimum) ?? default, ToInteger(Maximum) ?? default, Unit, 0)) - : InputEditor.CreateInteger(ToInteger(Minimum), ToInteger(Maximum), ToInteger(Step), ToInteger(StepFast), Hex, Unit, 0)) + ? Drag + ? (IEditor)DragEditor.CreateInteger(ToInteger(Minimum), ToInteger(Maximum), Speed ?? 0.25f, RelativeSpeed, + Unit, 0) + : SliderEditor.CreateInteger(ToInteger(Minimum) ?? default, ToInteger(Maximum) ?? default, Unit, 0) + : InputEditor.CreateInteger(ToInteger(Minimum), ToInteger(Maximum), ToInteger(Step), ToInteger(StepFast), + Hex, Unit, 0)) .WithFactorAndBias(ToInteger(Factor), ToInteger(Bias)); private IEditor CreateFloatEditor() where T : unmanaged, INumber, IPowerFunctions - => ((Drag || Slider) - ? (Drag - ? (IEditor)DragEditor.CreateFloat(ToFloat(Minimum), ToFloat(Maximum), Speed ?? 0.1f, RelativeSpeed, Precision, Unit, 0) - : SliderEditor.CreateFloat(ToFloat(Minimum) ?? default, ToFloat(Maximum) ?? default, Precision, Unit, 0)) - : InputEditor.CreateFloat(ToFloat(Minimum), ToFloat(Maximum), T.CreateSaturating(Step), T.CreateSaturating(StepFast), Precision, Unit, 0)) + => (Drag || Slider + ? Drag + ? (IEditor)DragEditor.CreateFloat(ToFloat(Minimum), ToFloat(Maximum), Speed ?? 0.1f, RelativeSpeed, + Precision, Unit, 0) + : SliderEditor.CreateFloat(ToFloat(Minimum) ?? default, ToFloat(Maximum) ?? default, Precision, Unit, 0) + : InputEditor.CreateFloat(ToFloat(Minimum), ToFloat(Maximum), T.CreateSaturating(Step), + T.CreateSaturating(StepFast), Precision, Unit, 0)) .WithExponent(T.CreateSaturating(Exponent)) .WithFactorAndBias(T.CreateSaturating(Factor), T.CreateSaturating(Bias)); diff --git a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.LegacyColorTable.cs b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.LegacyColorTable.cs index a2165760..0ff2b01f 100644 --- a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.LegacyColorTable.cs +++ b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.LegacyColorTable.cs @@ -110,9 +110,9 @@ public partial class MtrlTab } ImGui.TableNextColumn(); - using (ImRaii.PushFont(UiBuilder.MonoFont)) - { - ImUtf8.Text($"{(rowIdx >> 1) + 1,2:D}{"AB"[rowIdx & 1]}"); + using (ImRaii.PushFont(UiBuilder.MonoFont)) + { + ImUtf8.Text($"{(rowIdx >> 1) + 1,2:D}{"AB"[rowIdx & 1]}"); } ImGui.TableNextColumn(); diff --git a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.LivePreview.cs b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.LivePreview.cs index 3482e581..6089f2d5 100644 --- a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.LivePreview.cs +++ b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.LivePreview.cs @@ -12,20 +12,20 @@ namespace Penumbra.UI.AdvancedWindow.Materials; public partial class MtrlTab { - public readonly List MaterialPreviewers = new(4); - public readonly List ColorTablePreviewers = new(4); - public int HighlightedColorTablePair = -1; - public readonly Stopwatch HighlightTime = new(); + private readonly List _materialPreviewers = new(4); + private readonly List _colorTablePreviewers = new(4); + private int _highlightedColorTablePair = -1; + private readonly Stopwatch _highlightTime = new(); private void DrawMaterialLivePreviewRebind(bool disabled) { if (disabled) return; - if (ImGui.Button("Reload live preview")) + if (ImUtf8.Button("Reload live preview"u8)) BindToMaterialInstances(); - if (MaterialPreviewers.Count != 0 || ColorTablePreviewers.Count != 0) + if (_materialPreviewers.Count != 0 || _colorTablePreviewers.Count != 0) return; ImGui.SameLine(); @@ -34,7 +34,7 @@ public partial class MtrlTab "The current material has not been found on your character. Please check the Import from Screen tab for more information."u8); } - public unsafe void BindToMaterialInstances() + private unsafe void BindToMaterialInstances() { UnbindFromMaterialInstances(); @@ -50,7 +50,7 @@ public partial class MtrlTab try { - MaterialPreviewers.Add(new LiveMaterialPreviewer(_objects, materialInfo)); + _materialPreviewers.Add(new LiveMaterialPreviewer(_objects, materialInfo)); foundMaterials.Add((nint)material); } catch (InvalidOperationException) @@ -68,7 +68,7 @@ public partial class MtrlTab { try { - ColorTablePreviewers.Add(new LiveColorTablePreviewer(_objects, _framework, materialInfo)); + _colorTablePreviewers.Add(new LiveColorTablePreviewer(_objects, _framework, materialInfo)); } catch (InvalidOperationException) { @@ -81,53 +81,53 @@ public partial class MtrlTab private void UnbindFromMaterialInstances() { - foreach (var previewer in MaterialPreviewers) + foreach (var previewer in _materialPreviewers) previewer.Dispose(); - MaterialPreviewers.Clear(); + _materialPreviewers.Clear(); - foreach (var previewer in ColorTablePreviewers) + foreach (var previewer in _colorTablePreviewers) previewer.Dispose(); - ColorTablePreviewers.Clear(); + _colorTablePreviewers.Clear(); } private unsafe void UnbindFromDrawObjectMaterialInstances(CharacterBase* characterBase) { - for (var i = MaterialPreviewers.Count; i-- > 0;) + for (var i = _materialPreviewers.Count; i-- > 0;) { - var previewer = MaterialPreviewers[i]; + var previewer = _materialPreviewers[i]; if (previewer.DrawObject != characterBase) continue; previewer.Dispose(); - MaterialPreviewers.RemoveAt(i); + _materialPreviewers.RemoveAt(i); } - for (var i = ColorTablePreviewers.Count; i-- > 0;) + for (var i = _colorTablePreviewers.Count; i-- > 0;) { - var previewer = ColorTablePreviewers[i]; + var previewer = _colorTablePreviewers[i]; if (previewer.DrawObject != characterBase) continue; previewer.Dispose(); - ColorTablePreviewers.RemoveAt(i); + _colorTablePreviewers.RemoveAt(i); } } - public void SetShaderPackageFlags(uint shPkFlags) + private void SetShaderPackageFlags(uint shPkFlags) { - foreach (var previewer in MaterialPreviewers) + foreach (var previewer in _materialPreviewers) previewer.SetShaderPackageFlags(shPkFlags); } - public void SetMaterialParameter(uint parameterCrc, Index offset, Span value) + private void SetMaterialParameter(uint parameterCrc, Index offset, Span value) { - foreach (var previewer in MaterialPreviewers) + foreach (var previewer in _materialPreviewers) previewer.SetMaterialParameter(parameterCrc, offset, value); } - public void SetSamplerFlags(uint samplerCrc, uint samplerFlags) + private void SetSamplerFlags(uint samplerCrc, uint samplerFlags) { - foreach (var previewer in MaterialPreviewers) + foreach (var previewer in _materialPreviewers) previewer.SetSamplerFlags(samplerCrc, samplerFlags); } @@ -145,14 +145,14 @@ public partial class MtrlTab SetSamplerFlags(sampler.SamplerId, sampler.Flags); } - public void HighlightColorTablePair(int pairIdx) + private void HighlightColorTablePair(int pairIdx) { - var oldPairIdx = HighlightedColorTablePair; + var oldPairIdx = _highlightedColorTablePair; - if (HighlightedColorTablePair != pairIdx) + if (_highlightedColorTablePair != pairIdx) { - HighlightedColorTablePair = pairIdx; - HighlightTime.Restart(); + _highlightedColorTablePair = pairIdx; + _highlightTime.Restart(); } if (oldPairIdx >= 0) @@ -160,19 +160,6 @@ public partial class MtrlTab UpdateColorTableRowPreview(oldPairIdx << 1); UpdateColorTableRowPreview((oldPairIdx << 1) | 1); } - if (pairIdx >= 0) - { - UpdateColorTableRowPreview(pairIdx << 1); - UpdateColorTableRowPreview((pairIdx << 1) | 1); - } - } - - public void CancelColorTableHighlight() - { - var pairIdx = HighlightedColorTablePair; - - HighlightedColorTablePair = -1; - HighlightTime.Reset(); if (pairIdx >= 0) { @@ -181,9 +168,23 @@ public partial class MtrlTab } } - public void UpdateColorTableRowPreview(int rowIdx) + private void CancelColorTableHighlight() { - if (ColorTablePreviewers.Count == 0) + var pairIdx = _highlightedColorTablePair; + + _highlightedColorTablePair = -1; + _highlightTime.Reset(); + + if (pairIdx >= 0) + { + UpdateColorTableRowPreview(pairIdx << 1); + UpdateColorTableRowPreview((pairIdx << 1) | 1); + } + } + + private void UpdateColorTableRowPreview(int rowIdx) + { + if (_colorTablePreviewers.Count == 0) return; if (Mtrl.Table == null) @@ -192,7 +193,7 @@ public partial class MtrlTab var row = Mtrl.Table switch { LegacyColorTable legacyTable => new ColorTableRow(legacyTable[rowIdx]), - ColorTable table => table[rowIdx], + ColorTable table => table[rowIdx], _ => throw new InvalidOperationException($"Unsupported color table type {Mtrl.Table.GetType()}"), }; if (Mtrl.DyeTable != null) @@ -200,8 +201,8 @@ public partial class MtrlTab var dyeRow = Mtrl.DyeTable switch { LegacyColorDyeTable legacyDyeTable => new ColorDyeTableRow(legacyDyeTable[rowIdx]), - ColorDyeTable dyeTable => dyeTable[rowIdx], - _ => throw new InvalidOperationException($"Unsupported color dye table type {Mtrl.DyeTable.GetType()}"), + ColorDyeTable dyeTable => dyeTable[rowIdx], + _ => throw new InvalidOperationException($"Unsupported color dye table type {Mtrl.DyeTable.GetType()}"), }; if (dyeRow.Channel < StainService.ChannelCount) { @@ -213,21 +214,21 @@ public partial class MtrlTab } } - if (HighlightedColorTablePair << 1 == rowIdx) - ApplyHighlight(ref row, ColorId.InGameHighlight, (float)HighlightTime.Elapsed.TotalSeconds); - else if (((HighlightedColorTablePair << 1) | 1) == rowIdx) - ApplyHighlight(ref row, ColorId.InGameHighlight2, (float)HighlightTime.Elapsed.TotalSeconds); + if (_highlightedColorTablePair << 1 == rowIdx) + ApplyHighlight(ref row, ColorId.InGameHighlight, (float)_highlightTime.Elapsed.TotalSeconds); + else if (((_highlightedColorTablePair << 1) | 1) == rowIdx) + ApplyHighlight(ref row, ColorId.InGameHighlight2, (float)_highlightTime.Elapsed.TotalSeconds); - foreach (var previewer in ColorTablePreviewers) + foreach (var previewer in _colorTablePreviewers) { row[..].CopyTo(previewer.GetColorRow(rowIdx)); previewer.ScheduleUpdate(); } } - public void UpdateColorTablePreview() + private void UpdateColorTablePreview() { - if (ColorTablePreviewers.Count == 0) + if (_colorTablePreviewers.Count == 0) return; if (Mtrl.Table == null) @@ -237,7 +238,8 @@ public partial class MtrlTab var dyeRows = Mtrl.DyeTable != null ? ColorDyeTable.CastOrConvert(Mtrl.DyeTable) : null; if (dyeRows != null) { - ReadOnlySpan stainIds = [ + ReadOnlySpan stainIds = + [ _stainService.StainCombo1.CurrentSelection.Key, _stainService.StainCombo2.CurrentSelection.Key, ]; @@ -245,13 +247,14 @@ public partial class MtrlTab rows.ApplyDye(_stainService.GudStmFile, stainIds, dyeRows); } - if (HighlightedColorTablePair >= 0) + if (_highlightedColorTablePair >= 0) { - ApplyHighlight(ref rows[HighlightedColorTablePair << 1], ColorId.InGameHighlight, (float)HighlightTime.Elapsed.TotalSeconds); - ApplyHighlight(ref rows[(HighlightedColorTablePair << 1) | 1], ColorId.InGameHighlight2, (float)HighlightTime.Elapsed.TotalSeconds); + ApplyHighlight(ref rows[_highlightedColorTablePair << 1], ColorId.InGameHighlight, (float)_highlightTime.Elapsed.TotalSeconds); + ApplyHighlight(ref rows[(_highlightedColorTablePair << 1) | 1], ColorId.InGameHighlight2, + (float)_highlightTime.Elapsed.TotalSeconds); } - foreach (var previewer in ColorTablePreviewers) + foreach (var previewer in _colorTablePreviewers) { rows.AsHalves().CopyTo(previewer.ColorTable); previewer.ScheduleUpdate(); @@ -260,11 +263,11 @@ public partial class MtrlTab private static void ApplyHighlight(ref ColorTableRow row, ColorId colorId, float time) { - var level = (MathF.Sin(time * 2.0f * MathF.PI) + 2.0f) / 3.0f / 255.0f; - var baseColor = colorId.Value(); + var level = (MathF.Sin(time * 2.0f * MathF.PI) + 2.0f) / 3.0f / 255.0f; + var baseColor = colorId.Value(); var color = level * new Vector3(baseColor & 0xFF, (baseColor >> 8) & 0xFF, (baseColor >> 16) & 0xFF); var halfColor = (HalfColor)(color * color); - + row.DiffuseColor = halfColor; row.SpecularColor = halfColor; row.EmissiveColor = halfColor; diff --git a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ShaderPackage.cs b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ShaderPackage.cs index 21557939..ae57a122 100644 --- a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ShaderPackage.cs +++ b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ShaderPackage.cs @@ -21,8 +21,8 @@ public partial class MtrlTab // Apricot shader packages are unlisted because // 1. they cause severe performance/memory issues when calculating the effective shader set // 2. they probably aren't intended for use with materials anyway - internal static readonly IReadOnlyList StandardShaderPackages = new[] - { + private static readonly IReadOnlyList StandardShaderPackages = + [ "3dui.shpk", // "apricot_decal_dummy.shpk", // "apricot_decal_ring.shpk", @@ -80,35 +80,35 @@ public partial class MtrlTab "verticalfog.shpk", "water.shpk", "weather.shpk", - }; + ]; - private static readonly byte[] UnknownShadersString = Encoding.UTF8.GetBytes("Vertex Shaders: ???\nPixel Shaders: ???"); + private static readonly byte[] UnknownShadersString = "Vertex Shaders: ???\nPixel Shaders: ???"u8.ToArray(); private string[]? _shpkNames; - public string ShaderHeader = "Shader###Shader"; - public FullPath LoadedShpkPath = FullPath.Empty; - public string LoadedShpkPathName = string.Empty; - public string LoadedShpkDevkitPathName = string.Empty; - public string ShaderComment = string.Empty; - public ShpkFile? AssociatedShpk; - public bool ShpkLoading; - public JObject? AssociatedShpkDevkit; + private string _shaderHeader = "Shader###Shader"; + private FullPath _loadedShpkPath = FullPath.Empty; + private string _loadedShpkPathName = string.Empty; + private string _loadedShpkDevkitPathName = string.Empty; + private string _shaderComment = string.Empty; + private ShpkFile? _associatedShpk; + private bool _shpkLoading; + private JObject? _associatedShpkDevkit; - public readonly string LoadedBaseDevkitPathName; - public readonly JObject? AssociatedBaseDevkit; + private readonly string _loadedBaseDevkitPathName; + private readonly JObject? _associatedBaseDevkit; // Shader Key State - public readonly + private readonly List<(string Label, int Index, string Description, bool MonoFont, IReadOnlyList<(string Label, uint Value, string Description)> - Values)> ShaderKeys = new(16); + Values)> _shaderKeys = new(16); - public readonly HashSet VertexShaders = new(16); - public readonly HashSet PixelShaders = new(16); - public bool ShadersKnown; - public ReadOnlyMemory ShadersString = UnknownShadersString; + private readonly HashSet _vertexShaders = new(16); + private readonly HashSet _pixelShaders = new(16); + private bool _shadersKnown; + private ReadOnlyMemory _shadersString = UnknownShadersString; - public string[] GetShpkNames() + private string[] GetShpkNames() { if (null != _shpkNames) return _shpkNames; @@ -122,7 +122,7 @@ public partial class MtrlTab return _shpkNames; } - public FullPath FindAssociatedShpk(out string defaultPath, out Utf8GamePath defaultGamePath) + private FullPath FindAssociatedShpk(out string defaultPath, out Utf8GamePath defaultGamePath) { defaultPath = GamePaths.Shader.ShpkPath(Mtrl.ShaderPackage.Name); if (!Utf8GamePath.FromString(defaultPath, out defaultGamePath)) @@ -131,45 +131,45 @@ public partial class MtrlTab return _edit.FindBestMatch(defaultGamePath); } - public void LoadShpk(FullPath path) + private void LoadShpk(FullPath path) => Task.Run(() => DoLoadShpk(path)); private async Task DoLoadShpk(FullPath path) { - ShadersKnown = false; - ShaderHeader = $"Shader ({Mtrl.ShaderPackage.Name})###Shader"; - ShpkLoading = true; + _shadersKnown = false; + _shaderHeader = $"Shader ({Mtrl.ShaderPackage.Name})###Shader"; + _shpkLoading = true; try { var data = path.IsRooted ? await File.ReadAllBytesAsync(path.FullName) : _gameData.GetFile(path.InternalName.ToString())?.Data; - LoadedShpkPath = path; - AssociatedShpk = data?.Length > 0 ? new ShpkFile(data) : throw new Exception("Failure to load file data."); - LoadedShpkPathName = path.ToPath(); + _loadedShpkPath = path; + _associatedShpk = data?.Length > 0 ? new ShpkFile(data) : throw new Exception("Failure to load file data."); + _loadedShpkPathName = path.ToPath(); } catch (Exception e) { - LoadedShpkPath = FullPath.Empty; - LoadedShpkPathName = string.Empty; - AssociatedShpk = null; - Penumbra.Messager.NotificationMessage(e, $"Could not load {LoadedShpkPath.ToPath()}.", NotificationType.Error, false); + _loadedShpkPath = FullPath.Empty; + _loadedShpkPathName = string.Empty; + _associatedShpk = null; + Penumbra.Messager.NotificationMessage(e, $"Could not load {_loadedShpkPath.ToPath()}.", NotificationType.Error, false); } finally { - ShpkLoading = false; + _shpkLoading = false; } - if (LoadedShpkPath.InternalName.IsEmpty) + if (_loadedShpkPath.InternalName.IsEmpty) { - AssociatedShpkDevkit = null; - LoadedShpkDevkitPathName = string.Empty; + _associatedShpkDevkit = null; + _loadedShpkDevkitPathName = string.Empty; } else { - AssociatedShpkDevkit = - TryLoadShpkDevkit(Path.GetFileNameWithoutExtension(Mtrl.ShaderPackage.Name), out LoadedShpkDevkitPathName); + _associatedShpkDevkit = + TryLoadShpkDevkit(Path.GetFileNameWithoutExtension(Mtrl.ShaderPackage.Name), out _loadedShpkDevkitPathName); } UpdateShaderKeys(); @@ -178,9 +178,9 @@ public partial class MtrlTab private void UpdateShaderKeys() { - ShaderKeys.Clear(); - if (AssociatedShpk != null) - foreach (var key in AssociatedShpk.MaterialKeys) + _shaderKeys.Clear(); + if (_associatedShpk != null) + foreach (var key in _associatedShpk.MaterialKeys) { var keyName = Names.KnownNames.TryResolve(key.Id); var dkData = TryGetShpkDevkitData("ShaderKeys", key.Id, false); @@ -210,7 +210,7 @@ public partial class MtrlTab return string.Compare(x.Label, y.Label, StringComparison.Ordinal); }); - ShaderKeys.Add((hasDkLabel ? dkData!.Label : keyName.ToString(), mtrlKeyIndex, dkData?.Description ?? string.Empty, + _shaderKeys.Add((hasDkLabel ? dkData!.Label : keyName.ToString(), mtrlKeyIndex, dkData?.Description ?? string.Empty, !hasDkLabel, values)); } else @@ -218,7 +218,7 @@ public partial class MtrlTab { var keyName = Names.KnownNames.TryResolve(key.Category); var valueName = keyName.WithKnownSuffixes().TryResolve(Names.KnownNames, key.Value); - ShaderKeys.Add((keyName.ToString(), index, string.Empty, true, [(valueName.ToString(), key.Value, string.Empty)])); + _shaderKeys.Add((keyName.ToString(), index, string.Empty, true, [(valueName.ToString(), key.Value, string.Empty)])); } } @@ -232,27 +232,28 @@ public partial class MtrlTab passSet = []; byPassSets.Add(passId, passSet); } + passSet.Add(shaderIndex); } - VertexShaders.Clear(); - PixelShaders.Clear(); + _vertexShaders.Clear(); + _pixelShaders.Clear(); var vertexShadersByPass = new Dictionary>(); var pixelShadersByPass = new Dictionary>(); - if (AssociatedShpk == null || !AssociatedShpk.IsExhaustiveNodeAnalysisFeasible()) + if (_associatedShpk == null || !_associatedShpk.IsExhaustiveNodeAnalysisFeasible()) { - ShadersKnown = false; + _shadersKnown = false; } else { - ShadersKnown = true; - var systemKeySelectors = AllSelectors(AssociatedShpk.SystemKeys).ToArray(); - var sceneKeySelectors = AllSelectors(AssociatedShpk.SceneKeys).ToArray(); - var subViewKeySelectors = AllSelectors(AssociatedShpk.SubViewKeys).ToArray(); + _shadersKnown = true; + var systemKeySelectors = AllSelectors(_associatedShpk.SystemKeys).ToArray(); + var sceneKeySelectors = AllSelectors(_associatedShpk.SceneKeys).ToArray(); + var subViewKeySelectors = AllSelectors(_associatedShpk.SubViewKeys).ToArray(); var materialKeySelector = - BuildSelector(AssociatedShpk.MaterialKeys.Select(key => Mtrl.GetOrAddShaderKey(key.Id, key.DefaultValue).Value)); + BuildSelector(_associatedShpk.MaterialKeys.Select(key => Mtrl.GetOrAddShaderKey(key.Id, key.DefaultValue).Value)); foreach (var systemKeySelector in systemKeySelectors) { @@ -261,38 +262,39 @@ public partial class MtrlTab foreach (var subViewKeySelector in subViewKeySelectors) { var selector = BuildSelector(systemKeySelector, sceneKeySelector, materialKeySelector, subViewKeySelector); - var node = AssociatedShpk.GetNodeBySelector(selector); + var node = _associatedShpk.GetNodeBySelector(selector); if (node.HasValue) foreach (var pass in node.Value.Passes) { - AddShader(VertexShaders, vertexShadersByPass, pass.Id, (int)pass.VertexShader); - AddShader(PixelShaders, pixelShadersByPass, pass.Id, (int)pass.PixelShader); + AddShader(_vertexShaders, vertexShadersByPass, pass.Id, (int)pass.VertexShader); + AddShader(_pixelShaders, pixelShadersByPass, pass.Id, (int)pass.PixelShader); } else - ShadersKnown = false; + _shadersKnown = false; } } } } - if (ShadersKnown) + if (_shadersKnown) { var builder = new StringBuilder(); - foreach (var (passId, passVS) in vertexShadersByPass) + foreach (var (passId, passVertexShader) in vertexShadersByPass) { if (builder.Length > 0) builder.Append("\n\n"); var passName = Names.KnownNames.TryResolve(passId); - var shaders = passVS.OrderBy(i => i).Select(i => $"#{i}"); + var shaders = passVertexShader.OrderBy(i => i).Select(i => $"#{i}"); builder.Append($"Vertex Shaders ({passName}): {string.Join(", ", shaders)}"); - if (pixelShadersByPass.TryGetValue(passId, out var passPS)) + if (pixelShadersByPass.TryGetValue(passId, out var passPixelShader)) { - shaders = passPS.OrderBy(i => i).Select(i => $"#{i}"); + shaders = passPixelShader.OrderBy(i => i).Select(i => $"#{i}"); builder.Append($"\nPixel Shaders ({passName}): {string.Join(", ", shaders)}"); } } - foreach (var (passId, passPS) in pixelShadersByPass) + + foreach (var (passId, passPixelShader) in pixelShadersByPass) { if (vertexShadersByPass.ContainsKey(passId)) continue; @@ -301,22 +303,24 @@ public partial class MtrlTab builder.Append("\n\n"); var passName = Names.KnownNames.TryResolve(passId); - var shaders = passPS.OrderBy(i => i).Select(i => $"#{i}"); + var shaders = passPixelShader.OrderBy(i => i).Select(i => $"#{i}"); builder.Append($"Pixel Shaders ({passName}): {string.Join(", ", shaders)}"); } - ShadersString = Encoding.UTF8.GetBytes(builder.ToString()); + _shadersString = Encoding.UTF8.GetBytes(builder.ToString()); } else - ShadersString = UnknownShadersString; + { + _shadersString = UnknownShadersString; + } - ShaderComment = TryGetShpkDevkitData("Comment", null, true) ?? string.Empty; + _shaderComment = TryGetShpkDevkitData("Comment", null, true) ?? string.Empty; } private bool DrawShaderSection(bool disabled) { var ret = false; - if (ImGui.CollapsingHeader(ShaderHeader)) + if (ImGui.CollapsingHeader(_shaderHeader)) { ret |= DrawPackageNameInput(disabled); ret |= DrawShaderFlagsInput(disabled); @@ -325,20 +329,17 @@ public partial class MtrlTab DrawMaterialShaders(); } - if (!ShpkLoading && (AssociatedShpk == null || AssociatedShpkDevkit == null)) + if (!_shpkLoading && (_associatedShpk == null || _associatedShpkDevkit == null)) { ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2)); - if (AssociatedShpk == null) - { + if (_associatedShpk == null) ImUtf8.Text("Unable to find a suitable shader (.shpk) file for cross-references. Some functionality will be missing."u8, ImGuiUtil.HalfBlendText(0x80u)); // Half red - } else - { - ImUtf8.Text("No dev-kit file found for this material's shaders. Please install one for optimal editing experience, such as actual constant names instead of hexadecimal identifiers."u8, + ImUtf8.Text( + "No dev-kit file found for this material's shaders. Please install one for optimal editing experience, such as actual constant names instead of hexadecimal identifiers."u8, ImGuiUtil.HalfBlendText(0x8080u)); // Half yellow - } } return ret; @@ -358,14 +359,14 @@ public partial class MtrlTab if (c) foreach (var value in GetShpkNames()) { - if (ImGui.Selectable(value, value == Mtrl.ShaderPackage.Name)) - { - Mtrl.ShaderPackage.Name = value; - ret = true; - AssociatedShpk = null; - LoadedShpkPath = FullPath.Empty; - LoadShpk(FindAssociatedShpk(out _, out _)); - } + if (!ImGui.Selectable(value, value == Mtrl.ShaderPackage.Name)) + continue; + + Mtrl.ShaderPackage.Name = value; + ret = true; + _associatedShpk = null; + _loadedShpkPath = FullPath.Empty; + LoadShpk(FindAssociatedShpk(out _, out _)); } return ret; @@ -391,23 +392,23 @@ public partial class MtrlTab private void DrawCustomAssociations() { const string tooltip = "Click to copy file path to clipboard."; - var text = AssociatedShpk == null + var text = _associatedShpk == null ? "Associated .shpk file: None" - : $"Associated .shpk file: {LoadedShpkPathName}"; - var devkitText = AssociatedShpkDevkit == null + : $"Associated .shpk file: {_loadedShpkPathName}"; + var devkitText = _associatedShpkDevkit == null ? "Associated dev-kit file: None" - : $"Associated dev-kit file: {LoadedShpkDevkitPathName}"; - var baseDevkitText = AssociatedBaseDevkit == null + : $"Associated dev-kit file: {_loadedShpkDevkitPathName}"; + var baseDevkitText = _associatedBaseDevkit == null ? "Base dev-kit file: None" - : $"Base dev-kit file: {LoadedBaseDevkitPathName}"; + : $"Base dev-kit file: {_loadedBaseDevkitPathName}"; ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2)); - ImGuiUtil.CopyOnClickSelectable(text, LoadedShpkPathName, tooltip); - ImGuiUtil.CopyOnClickSelectable(devkitText, LoadedShpkDevkitPathName, tooltip); - ImGuiUtil.CopyOnClickSelectable(baseDevkitText, LoadedBaseDevkitPathName, tooltip); + ImUtf8.CopyOnClickSelectable(text, _loadedShpkPathName, tooltip); + ImUtf8.CopyOnClickSelectable(devkitText, _loadedShpkDevkitPathName, tooltip); + ImUtf8.CopyOnClickSelectable(baseDevkitText, _loadedBaseDevkitPathName, tooltip); - if (ImGui.Button("Associate Custom .shpk File")) + if (ImUtf8.Button("Associate Custom .shpk File"u8)) _fileDialog.OpenFilePicker("Associate Custom .shpk File...", ".shpk", (success, name) => { if (success) @@ -416,15 +417,15 @@ public partial class MtrlTab var moddedPath = FindAssociatedShpk(out var defaultPath, out var gamePath); ImGui.SameLine(); - if (ImGuiUtil.DrawDisabledButton("Associate Default .shpk File", Vector2.Zero, moddedPath.ToPath(), - moddedPath.Equals(LoadedShpkPath))) + if (ImUtf8.ButtonEx("Associate Default .shpk File"u8, moddedPath.ToPath(), Vector2.Zero, + moddedPath.Equals(_loadedShpkPath))) LoadShpk(moddedPath); if (!gamePath.Path.Equals(moddedPath.InternalName)) { ImGui.SameLine(); - if (ImGuiUtil.DrawDisabledButton("Associate Unmodded .shpk File", Vector2.Zero, defaultPath, - gamePath.Path.Equals(LoadedShpkPath.InternalName))) + if (ImUtf8.ButtonEx("Associate Unmodded .shpk File", defaultPath, Vector2.Zero, + gamePath.Path.Equals(_loadedShpkPath.InternalName))) LoadShpk(new FullPath(gamePath)); } @@ -433,22 +434,23 @@ public partial class MtrlTab private bool DrawMaterialShaderKeys(bool disabled) { - if (ShaderKeys.Count == 0) + if (_shaderKeys.Count == 0) return false; var ret = false; - foreach (var (label, index, description, monoFont, values) in ShaderKeys) + foreach (var (label, index, description, monoFont, values) in _shaderKeys) { using var font = ImRaii.PushFont(UiBuilder.MonoFont, monoFont); ref var key = ref Mtrl.ShaderPackage.ShaderKeys[index]; - var shpkKey = AssociatedShpk?.GetMaterialKeyById(key.Category); + using var id = ImUtf8.PushId((int)key.Category); + var shpkKey = _associatedShpk?.GetMaterialKeyById(key.Category); var currentValue = key.Value; var (currentLabel, _, currentDescription) = values.FirstOrNull(v => v.Value == currentValue) ?? ($"0x{currentValue:X8}", currentValue, string.Empty); if (!disabled && shpkKey.HasValue) { ImGui.SetNextItemWidth(UiHelpers.Scale * 250.0f); - using (var c = ImRaii.Combo($"##{key.Category:X8}", currentLabel)) + using (var c = ImUtf8.Combo(""u8, currentLabel)) { if (c) foreach (var (valueLabel, value, valueDescription) in values) @@ -469,16 +471,16 @@ public partial class MtrlTab if (description.Length > 0) ImGuiUtil.LabeledHelpMarker(label, description); else - ImGui.TextUnformatted(label); + ImUtf8.Text(label); } else if (description.Length > 0 || currentDescription.Length > 0) { - ImGuiUtil.LabeledHelpMarker($"{label}: {currentLabel}", + ImUtf8.LabeledHelpMarker($"{label}: {currentLabel}", description + (description.Length > 0 && currentDescription.Length > 0 ? "\n\n" : string.Empty) + currentDescription); } else { - ImGui.TextUnformatted($"{label}: {currentLabel}"); + ImUtf8.Text($"{label}: {currentLabel}"); } } @@ -487,19 +489,19 @@ public partial class MtrlTab private void DrawMaterialShaders() { - if (AssociatedShpk == null) + if (_associatedShpk == null) return; using (var node = ImUtf8.TreeNode("Candidate Shaders"u8)) { if (node) - ImUtf8.Text(ShadersString.Span); + ImUtf8.Text(_shadersString.Span); } - if (ShaderComment.Length > 0) + if (_shaderComment.Length > 0) { ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2)); - ImGui.TextUnformatted(ShaderComment); + ImUtf8.Text(_shaderComment); } } } diff --git a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.Textures.cs b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.Textures.cs index 3181dafe..7ab2900d 100644 --- a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.Textures.cs +++ b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.Textures.cs @@ -23,7 +23,7 @@ public partial class MtrlTab { Textures.Clear(); SamplerIds.Clear(); - if (AssociatedShpk == null) + if (_associatedShpk == null) { SamplerIds.UnionWith(Mtrl.ShaderPackage.Samplers.Select(sampler => sampler.SamplerId)); if (Mtrl.Table != null) @@ -34,11 +34,11 @@ public partial class MtrlTab } else { - foreach (var index in VertexShaders) - SamplerIds.UnionWith(AssociatedShpk.VertexShaders[index].Samplers.Select(sampler => sampler.Id)); - foreach (var index in PixelShaders) - SamplerIds.UnionWith(AssociatedShpk.PixelShaders[index].Samplers.Select(sampler => sampler.Id)); - if (!ShadersKnown) + foreach (var index in _vertexShaders) + SamplerIds.UnionWith(_associatedShpk.VertexShaders[index].Samplers.Select(sampler => sampler.Id)); + foreach (var index in _pixelShaders) + SamplerIds.UnionWith(_associatedShpk.PixelShaders[index].Samplers.Select(sampler => sampler.Id)); + if (!_shadersKnown) { SamplerIds.UnionWith(Mtrl.ShaderPackage.Samplers.Select(sampler => sampler.SamplerId)); if (Mtrl.Table != null) @@ -47,11 +47,11 @@ public partial class MtrlTab foreach (var samplerId in SamplerIds) { - var shpkSampler = AssociatedShpk.GetSamplerById(samplerId); + var shpkSampler = _associatedShpk.GetSamplerById(samplerId); if (shpkSampler is not { Slot: 2 }) continue; - var dkData = TryGetShpkDevkitData("Samplers", samplerId, true); + var dkData = TryGetShpkDevkitData("Samplers", samplerId, true); var hasDkLabel = !string.IsNullOrEmpty(dkData?.Label); var sampler = Mtrl.GetOrAddSampler(samplerId, dkData?.DefaultTexture ?? string.Empty, out var samplerIndex); @@ -95,9 +95,12 @@ public partial class MtrlTab private static ReadOnlySpan TextureAddressModeTooltip(TextureAddressMode addressMode) => addressMode switch { - TextureAddressMode.Wrap => "Tile the texture at every UV integer junction.\n\nFor example, for U values between 0 and 3, the texture is repeated three times."u8, - TextureAddressMode.Mirror => "Flip the texture at every UV integer junction.\n\nFor U values between 0 and 1, for example, the texture is addressed normally; between 1 and 2, the texture is mirrored; between 2 and 3, the texture is normal again; and so on."u8, - TextureAddressMode.Clamp => "Texture coordinates outside the range [0.0, 1.0] are set to the texture color at 0.0 or 1.0, respectively."u8, + TextureAddressMode.Wrap => + "Tile the texture at every UV integer junction.\n\nFor example, for U values between 0 and 3, the texture is repeated three times."u8, + TextureAddressMode.Mirror => + "Flip the texture at every UV integer junction.\n\nFor U values between 0 and 1, for example, the texture is addressed normally; between 1 and 2, the texture is mirrored; between 2 and 3, the texture is normal again; and so on."u8, + TextureAddressMode.Clamp => + "Texture coordinates outside the range [0.0, 1.0] are set to the texture color at 0.0 or 1.0, respectively."u8, TextureAddressMode.Border => "Texture coordinates outside the range [0.0, 1.0] are set to the border color (generally black)."u8, _ => ""u8, }; @@ -167,7 +170,7 @@ public partial class MtrlTab return ret; } - + private static bool ComboTextureAddressMode(ReadOnlySpan label, ref TextureAddressMode value) { using var c = ImUtf8.Combo(label, value.ToString()); @@ -202,7 +205,7 @@ public partial class MtrlTab ret = true; } - ref var samplerFlags = ref SamplerFlags.Wrap(ref sampler.Flags); + ref var samplerFlags = ref Wrap(ref sampler.Flags); ImGui.SetNextItemWidth(UiHelpers.Scale * 100.0f); var addressMode = samplerFlags.UAddressMode; diff --git a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.cs b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.cs index 2d4e93f1..6e16de99 100644 --- a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.cs +++ b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.cs @@ -4,7 +4,6 @@ using OtterGui; using OtterGui.Raii; using OtterGui.Text; using OtterGui.Widgets; -using Penumbra.GameData; using Penumbra.GameData.Files; using Penumbra.GameData.Files.MaterialStructs; using Penumbra.GameData.Interop; @@ -21,7 +20,7 @@ public sealed partial class MtrlTab : IWritable, IDisposable private const int ShpkPrefixLength = 16; private static readonly CiByteString ShpkPrefix = CiByteString.FromSpanUnsafe("shader/sm5/shpk/"u8, true, true, true); - + private readonly IDataManager _gameData; private readonly IFramework _framework; private readonly ObjectManager _objects; @@ -40,7 +39,8 @@ public sealed partial class MtrlTab : IWritable, IDisposable private bool _updateOnNextFrame; public unsafe MtrlTab(IDataManager gameData, IFramework framework, ObjectManager objects, CharacterBaseDestructor characterBaseDestructor, - StainService stainService, ResourceTreeFactory resourceTreeFactory, FileDialogService fileDialog, MaterialTemplatePickers materialTemplatePickers, + StainService stainService, ResourceTreeFactory resourceTreeFactory, FileDialogService fileDialog, + MaterialTemplatePickers materialTemplatePickers, Configuration config, ModEditWindow edit, MtrlFile file, string filePath, bool writable) { _gameData = gameData; @@ -53,11 +53,11 @@ public sealed partial class MtrlTab : IWritable, IDisposable _materialTemplatePickers = materialTemplatePickers; _config = config; - _edit = edit; - Mtrl = file; - FilePath = filePath; - Writable = writable; - AssociatedBaseDevkit = TryLoadShpkDevkit("_base", out LoadedBaseDevkitPathName); + _edit = edit; + Mtrl = file; + FilePath = filePath; + Writable = writable; + _associatedBaseDevkit = TryLoadShpkDevkit("_base", out _loadedBaseDevkitPathName); Update(); LoadShpk(FindAssociatedShpk(out _, out _)); if (writable) @@ -118,7 +118,7 @@ public sealed partial class MtrlTab : IWritable, IDisposable using var dis = ImRaii.Disabled(disabled); var tmp = shaderFlags.EnableTransparency; - if (ImGui.Checkbox("Enable Transparency", ref tmp)) + if (ImUtf8.Checkbox("Enable Transparency"u8, ref tmp)) { shaderFlags.EnableTransparency = tmp; ret = true; @@ -127,14 +127,14 @@ public sealed partial class MtrlTab : IWritable, IDisposable ImGui.SameLine(200 * UiHelpers.Scale + ImGui.GetStyle().ItemSpacing.X + ImGui.GetStyle().WindowPadding.X); tmp = shaderFlags.HideBackfaces; - if (ImGui.Checkbox("Hide Backfaces", ref tmp)) + if (ImUtf8.Checkbox("Hide Backfaces"u8, ref tmp)) { shaderFlags.HideBackfaces = tmp; ret = true; SetShaderPackageFlags(Mtrl.ShaderPackage.Flags); } - if (ShpkLoading) + if (_shpkLoading) { ImGui.SameLine(400 * UiHelpers.Scale + 2 * ImGui.GetStyle().ItemSpacing.X + ImGui.GetStyle().WindowPadding.X); @@ -147,32 +147,32 @@ public sealed partial class MtrlTab : IWritable, IDisposable private void DrawOtherMaterialDetails(bool _) { - if (!ImGui.CollapsingHeader("Further Content")) + if (!ImUtf8.CollapsingHeader("Further Content"u8)) return; - using (var sets = ImRaii.TreeNode("UV Sets", ImGuiTreeNodeFlags.DefaultOpen)) + using (var sets = ImUtf8.TreeNode("UV Sets"u8, ImGuiTreeNodeFlags.DefaultOpen)) { if (sets) foreach (var set in Mtrl.UvSets) - ImRaii.TreeNode($"#{set.Index:D2} - {set.Name}", ImGuiTreeNodeFlags.Leaf).Dispose(); + ImUtf8.TreeNode($"#{set.Index:D2} - {set.Name}", ImGuiTreeNodeFlags.Leaf).Dispose(); } - using (var sets = ImRaii.TreeNode("Color Sets", ImGuiTreeNodeFlags.DefaultOpen)) + using (var sets = ImUtf8.TreeNode("Color Sets"u8, ImGuiTreeNodeFlags.DefaultOpen)) { if (sets) foreach (var set in Mtrl.ColorSets) - ImRaii.TreeNode($"#{set.Index:D2} - {set.Name}", ImGuiTreeNodeFlags.Leaf).Dispose(); + ImUtf8.TreeNode($"#{set.Index:D2} - {set.Name}", ImGuiTreeNodeFlags.Leaf).Dispose(); } if (Mtrl.AdditionalData.Length <= 0) return; - using var t = ImRaii.TreeNode($"Additional Data (Size: {Mtrl.AdditionalData.Length})###AdditionalData"); + using var t = ImUtf8.TreeNode($"Additional Data (Size: {Mtrl.AdditionalData.Length})###AdditionalData"); if (t) Widget.DrawHexViewer(Mtrl.AdditionalData); } - public void Update() + private void Update() { UpdateShaders(); UpdateTextures(); @@ -187,12 +187,12 @@ public sealed partial class MtrlTab : IWritable, IDisposable } public bool Valid - => ShadersKnown && Mtrl.Valid; + => _shadersKnown && Mtrl.Valid; public byte[] Write() { var output = Mtrl.Clone(); - output.GarbageCollect(AssociatedShpk, SamplerIds); + output.GarbageCollect(_associatedShpk, SamplerIds); return output.Write(); } diff --git a/Penumbra/UI/AdvancedWindow/Materials/MtrlTabFactory.cs b/Penumbra/UI/AdvancedWindow/Materials/MtrlTabFactory.cs index af8b7db2..09db4277 100644 --- a/Penumbra/UI/AdvancedWindow/Materials/MtrlTabFactory.cs +++ b/Penumbra/UI/AdvancedWindow/Materials/MtrlTabFactory.cs @@ -8,9 +8,16 @@ using Penumbra.Services; namespace Penumbra.UI.AdvancedWindow.Materials; -public sealed class MtrlTabFactory(IDataManager gameData, IFramework framework, ObjectManager objects, - CharacterBaseDestructor characterBaseDestructor, StainService stainService, ResourceTreeFactory resourceTreeFactory, - FileDialogService fileDialog, MaterialTemplatePickers materialTemplatePickers, Configuration config) : IUiService +public sealed class MtrlTabFactory( + IDataManager gameData, + IFramework framework, + ObjectManager objects, + CharacterBaseDestructor characterBaseDestructor, + StainService stainService, + ResourceTreeFactory resourceTreeFactory, + FileDialogService fileDialog, + MaterialTemplatePickers materialTemplatePickers, + Configuration config) : IUiService { public MtrlTab Create(ModEditWindow edit, MtrlFile file, string filePath, bool writable) => new(gameData, framework, objects, characterBaseDestructor, stainService, resourceTreeFactory, fileDialog, diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.cs index ee883daf..59b38465 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.cs @@ -3,6 +3,7 @@ using Dalamud.Interface.Utility; using ImGuiNET; using OtterGui; using OtterGui.Raii; +using OtterGui.Text; using Penumbra.UI.AdvancedWindow.Materials; namespace Penumbra.UI.AdvancedWindow; @@ -24,7 +25,7 @@ public partial class ModEditWindow if (_editor.Files.Mdl.Count == 0) return; - using var tab = ImRaii.TabItem("Material Reassignment"); + using var tab = ImUtf8.TabItem("Material Reassignment"u8); if (!tab) return; @@ -32,45 +33,43 @@ public partial class ModEditWindow MaterialSuffix.Draw(_editor, ImGuiHelpers.ScaledVector2(175, 0)); ImGui.NewLine(); - using var child = ImRaii.Child("##mdlFiles", -Vector2.One, true); + using var child = ImUtf8.Child("##mdlFiles"u8, -Vector2.One, true); if (!child) return; - using var table = ImRaii.Table("##files", 4, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, -Vector2.One); + using var table = ImUtf8.Table("##files"u8, 4, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, -Vector2.One); if (!table) return; - var iconSize = ImGui.GetFrameHeight() * Vector2.One; foreach (var (info, idx) in _editor.MdlMaterialEditor.ModelFiles.WithIndex()) { using var id = ImRaii.PushId(idx); ImGui.TableNextColumn(); - if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Save.ToIconString(), iconSize, - "Save the changed mdl file.\nUse at own risk!", !info.Changed, true)) + if (ImUtf8.IconButton(FontAwesomeIcon.Save, "Save the changed mdl file.\nUse at own risk!"u8, disabled: !info.Changed)) info.Save(_editor.Compactor); ImGui.TableNextColumn(); - if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Recycle.ToIconString(), iconSize, - "Restore current changes to default.", !info.Changed, true)) + if (ImUtf8.IconButton(FontAwesomeIcon.Recycle, "Restore current changes to default."u8, disabled: !info.Changed)) info.Restore(); ImGui.TableNextColumn(); - ImGui.TextUnformatted(info.Path.FullName[(Mod!.ModPath.FullName.Length + 1)..]); + ImUtf8.Text(info.Path.InternalName.Span[(Mod!.ModPath.FullName.Length + 1)..]); ImGui.TableNextColumn(); ImGui.SetNextItemWidth(400 * UiHelpers.Scale); var tmp = info.CurrentMaterials[0]; - if (ImGui.InputText("##0", ref tmp, 64)) + if (ImUtf8.InputText("##0"u8, ref tmp)) info.SetMaterial(tmp, 0); for (var i = 1; i < info.Count; ++i) { + using var id2 = ImUtf8.PushId(i); ImGui.TableNextColumn(); ImGui.TableNextColumn(); ImGui.TableNextColumn(); ImGui.TableNextColumn(); ImGui.SetNextItemWidth(400 * UiHelpers.Scale); tmp = info.CurrentMaterials[i]; - if (ImGui.InputText($"##{i}", ref tmp, 64)) + if (ImUtf8.InputText(""u8, ref tmp)) info.SetMaterial(tmp, i); } } diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs index 8a1c729c..41f1da26 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs @@ -10,7 +10,6 @@ using Penumbra.GameData.Interop; using Penumbra.String; using static Penumbra.GameData.Files.ShpkFile; using OtterGui.Widgets; -using Penumbra.GameData.Files.ShaderStructs; using OtterGui.Text; using Penumbra.GameData.Structs; @@ -56,21 +55,17 @@ public partial class ModEditWindow private static void DrawShaderPackageSummary(ShpkTab tab) { if (tab.Shpk.IsLegacy) - { ImUtf8.Text("This legacy shader package will not work in the current version of the game. Do not attempt to load it.", ImGuiUtil.HalfBlendText(0x80u)); // Half red - } - ImGui.TextUnformatted(tab.Header); + ImUtf8.Text(tab.Header); if (!tab.Shpk.Disassembled) - { ImUtf8.Text("Your system doesn't support disassembling shaders. Some functionality will be missing.", ImGuiUtil.HalfBlendText(0x80u)); // Half red - } } private static void DrawShaderExportButton(ShpkTab tab, string objectName, Shader shader, int idx) { - if (!ImGui.Button($"Export Shader Program Blob ({shader.Blob.Length} bytes)")) + if (!ImUtf8.Button($"Export Shader Program Blob ({shader.Blob.Length} bytes)")) return; var defaultName = objectName[0] switch @@ -106,7 +101,7 @@ public partial class ModEditWindow private static void DrawShaderImportButton(ShpkTab tab, string objectName, Shader[] shaders, int idx) { - if (!ImGui.Button("Replace Shader Program Blob")) + if (!ImUtf8.Button("Replace Shader Program Blob"u8)) return; tab.FileDialog.OpenFilePicker($"Replace {objectName} #{idx} Program Blob...", "Shader Program Blobs{.o,.cso,.dxbc,.dxil}", @@ -145,8 +140,8 @@ public partial class ModEditWindow private static unsafe void DrawRawDisassembly(Shader shader) { - using var t2 = ImRaii.TreeNode("Raw Program Disassembly"); - if (!t2) + using var tree = ImUtf8.TreeNode("Raw Program Disassembly"u8); + if (!tree) return; using var font = ImRaii.PushFont(UiBuilder.MonoFont); @@ -164,31 +159,34 @@ public partial class ModEditWindow { foreach (var (key, keyIdx) in shader.SystemValues!.WithIndex()) { - ImRaii.TreeNode($"Used with System Key {tab.TryResolveName(tab.Shpk.SystemKeys[keyIdx].Id)} \u2208 {{ {tab.NameSetToString(key)} }}", + ImUtf8.TreeNode( + $"Used with System Key {tab.TryResolveName(tab.Shpk.SystemKeys[keyIdx].Id)} \u2208 {{ {tab.NameSetToString(key)} }}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); } foreach (var (key, keyIdx) in shader.SceneValues!.WithIndex()) { - ImRaii.TreeNode($"Used with Scene Key {tab.TryResolveName(tab.Shpk.SceneKeys[keyIdx].Id)} \u2208 {{ {tab.NameSetToString(key)} }}", + ImUtf8.TreeNode( + $"Used with Scene Key {tab.TryResolveName(tab.Shpk.SceneKeys[keyIdx].Id)} \u2208 {{ {tab.NameSetToString(key)} }}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); } foreach (var (key, keyIdx) in shader.MaterialValues!.WithIndex()) { - ImRaii.TreeNode($"Used with Material Key {tab.TryResolveName(tab.Shpk.MaterialKeys[keyIdx].Id)} \u2208 {{ {tab.NameSetToString(key)} }}", + ImUtf8.TreeNode( + $"Used with Material Key {tab.TryResolveName(tab.Shpk.MaterialKeys[keyIdx].Id)} \u2208 {{ {tab.NameSetToString(key)} }}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); } foreach (var (key, keyIdx) in shader.SubViewValues!.WithIndex()) { - ImRaii.TreeNode($"Used with Sub-View Key #{keyIdx} \u2208 {{ {tab.NameSetToString(key)} }}", + ImUtf8.TreeNode($"Used with Sub-View Key #{keyIdx} \u2208 {{ {tab.NameSetToString(key)} }}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); } } } - ImRaii.TreeNode($"Used in Passes: {tab.NameSetToString(shader.Passes)}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); + ImUtf8.TreeNode($"Used in Passes: {tab.NameSetToString(shader.Passes)}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); } private static void DrawShaderPackageFilterSection(ShpkTab tab) @@ -215,19 +213,20 @@ public partial class ModEditWindow { if (values.PossibleValues == null) { - ImRaii.TreeNode(label, ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); + ImUtf8.TreeNode(label, ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); return; } - using var node = ImRaii.TreeNode(label); + using var node = ImUtf8.TreeNode(label); if (!node) return; foreach (var value in values.PossibleValues) { var contains = values.Contains(value); - if (!ImGui.Checkbox($"{tab.TryResolveName(value)}", ref contains)) + if (!ImUtf8.Checkbox($"{tab.TryResolveName(value)}", ref contains)) continue; + if (contains) { if (values.AddExisting(value)) @@ -249,7 +248,7 @@ public partial class ModEditWindow private static bool DrawShaderPackageShaderArray(ShpkTab tab, string objectName, Shader[] shaders, bool disabled) { - if (shaders.Length == 0 || !ImGui.CollapsingHeader($"{objectName}s")) + if (shaders.Length == 0 || !ImUtf8.CollapsingHeader($"{objectName}s")) return false; var ret = false; @@ -259,7 +258,7 @@ public partial class ModEditWindow if (!tab.IsFilterMatch(shader)) continue; - using var t = ImRaii.TreeNode($"{objectName} #{idx}"); + using var t = ImUtf8.TreeNode($"{objectName} #{idx}"); if (!t) continue; @@ -270,20 +269,20 @@ public partial class ModEditWindow DrawShaderImportButton(tab, objectName, shaders, idx); } - ret |= DrawShaderPackageResourceArray("Constant Buffers", "slot", true, shader.Constants, false, true); - ret |= DrawShaderPackageResourceArray("Samplers", "slot", false, shader.Samplers, false, true); + ret |= DrawShaderPackageResourceArray("Constant Buffers", "slot", true, shader.Constants, false, true); + ret |= DrawShaderPackageResourceArray("Samplers", "slot", false, shader.Samplers, false, true); if (!tab.Shpk.IsLegacy) - ret |= DrawShaderPackageResourceArray("Textures", "slot", false, shader.Textures, false, true); - ret |= DrawShaderPackageResourceArray("Unordered Access Views", "slot", true, shader.Uavs, false, true); + ret |= DrawShaderPackageResourceArray("Textures", "slot", false, shader.Textures, false, true); + ret |= DrawShaderPackageResourceArray("Unordered Access Views", "slot", true, shader.Uavs, false, true); if (shader.DeclaredInputs != 0) - ImRaii.TreeNode($"Declared Inputs: {shader.DeclaredInputs}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); + ImUtf8.TreeNode($"Declared Inputs: {shader.DeclaredInputs}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); if (shader.UsedInputs != 0) - ImRaii.TreeNode($"Used Inputs: {shader.UsedInputs}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); + ImUtf8.TreeNode($"Used Inputs: {shader.UsedInputs}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); if (shader.AdditionalHeader.Length > 8) { - using var t2 = ImRaii.TreeNode($"Additional Header (Size: {shader.AdditionalHeader.Length})###AdditionalHeader"); + using var t2 = ImUtf8.TreeNode($"Additional Header (Size: {shader.AdditionalHeader.Length})###AdditionalHeader"); if (t2) Widget.DrawHexViewer(shader.AdditionalHeader); } @@ -313,23 +312,28 @@ public partial class ModEditWindow var usedString = UsedComponentString(withSize, false, resource); if (usedString.Length > 0) { - ImRaii.TreeNode(hasFilter ? $"Globally Used: {usedString}" : $"Used: {usedString}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); + ImUtf8.TreeNode(hasFilter ? $"Globally Used: {usedString}" : $"Used: {usedString}", + ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); if (hasFilter) { var filteredUsedString = UsedComponentString(withSize, true, resource); if (filteredUsedString.Length > 0) - ImRaii.TreeNode($"Used within Filters: {filteredUsedString}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); + ImUtf8.TreeNode($"Used within Filters: {filteredUsedString}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet) + .Dispose(); else - ImRaii.TreeNode("Unused within Filters", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); + ImUtf8.TreeNode("Unused within Filters"u8, ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); } } else - ImRaii.TreeNode(hasFilter ? "Globally Unused" : "Unused", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); + { + ImUtf8.TreeNode(hasFilter ? "Globally Unused"u8 : "Unused"u8, ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); + } return ret; } - private static bool DrawShaderPackageResourceArray(string arrayName, string slotLabel, bool withSize, Resource[] resources, bool hasFilter, bool disabled) + private static bool DrawShaderPackageResourceArray(string arrayName, string slotLabel, bool withSize, Resource[] resources, bool hasFilter, + bool disabled) { if (resources.Length == 0) return false; @@ -345,8 +349,8 @@ public partial class ModEditWindow var name = $"#{idx}: {buf.Name} (ID: 0x{buf.Id:X8}), {slotLabel}: {buf.Slot}" + (withSize ? $", size: {buf.Size} registers###{idx}: {buf.Name} (ID: 0x{buf.Id:X8})" : string.Empty); using var font = ImRaii.PushFont(UiBuilder.MonoFont); - using var t2 = ImRaii.TreeNode(name, !disabled || buf.Used != null ? 0 : ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet); - font.Dispose(); + using var t2 = ImUtf8.TreeNode(name, !disabled || buf.Used != null ? 0 : ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet); + font.Pop(); if (t2) ret |= DrawShaderPackageResource(slotLabel, withSize, ref buf, hasFilter, disabled); } @@ -361,7 +365,7 @@ public partial class ModEditWindow + new Vector2(ImGui.CalcTextSize(label).X + 3 * ImGui.GetStyle().ItemInnerSpacing.X + ImGui.GetFrameHeight(), ImGui.GetStyle().FramePadding.Y); - var ret = ImGui.CollapsingHeader(label); + var ret = ImUtf8.CollapsingHeader(label); ImGui.GetWindowDrawList() .AddText(UiBuilder.DefaultFont, UiBuilder.DefaultFont.FontSize, pos, ImGui.GetColorU32(ImGuiCol.Text), "Layout"); return ret; @@ -374,7 +378,7 @@ public partial class ModEditWindow if (isSizeWellDefined) return true; - ImGui.TextUnformatted(materialParams.HasValue + ImUtf8.Text(materialParams.HasValue ? $"Buffer size mismatch: {file.MaterialParamsSize} bytes ≠ {materialParams.Value.Size} registers ({materialParams.Value.Size << 4} bytes)" : $"Buffer size mismatch: {file.MaterialParamsSize} bytes, not a multiple of 16"); return false; @@ -382,7 +386,7 @@ public partial class ModEditWindow private static bool DrawShaderPackageMaterialMatrix(ShpkTab tab, bool disabled) { - ImGui.TextUnformatted(tab.Shpk.Disassembled + ImUtf8.Text(tab.Shpk.Disassembled ? "Parameter positions (continuations are grayed out, globally unused values are red, unused values within filters are yellow):" : "Parameter positions (continuations are grayed out):"); @@ -398,10 +402,7 @@ public partial class ModEditWindow ImGui.TableSetupColumn("w", ImGuiTableColumnFlags.WidthFixed, 250 * UiHelpers.Scale); ImGui.TableHeadersRow(); - var textColorStart = ImGui.GetColorU32(ImGuiCol.Text); - var textColorCont = ImGuiUtil.HalfTransparent(textColorStart); // Half opacity - var textColorUnusedStart = ImGuiUtil.HalfBlend(textColorStart, 0x80u); // Half red - var textColorUnusedCont = ImGuiUtil.HalfTransparent(textColorUnusedStart); + var textColorStart = ImGui.GetColorU32(ImGuiCol.Text); var ret = false; for (var i = 0; i < tab.Matrix.GetLength(0); ++i) @@ -420,12 +421,12 @@ public partial class ModEditWindow color = ImGuiUtil.HalfTransparent(color); // Half opacity using var _ = ImRaii.PushId(i * 4 + j); var deletable = !disabled && idx >= 0; - using (var font = ImRaii.PushFont(UiBuilder.MonoFont, tooltip.Length > 0)) + using (ImRaii.PushFont(UiBuilder.MonoFont, tooltip.Length > 0)) { - using (var c = ImRaii.PushColor(ImGuiCol.Text, color)) + using (ImRaii.PushColor(ImGuiCol.Text, color)) { ImGui.TableNextColumn(); - ImGui.Selectable(name); + ImUtf8.Selectable(name); if (deletable && ImGui.IsItemClicked(ImGuiMouseButton.Right) && ImGui.GetIO().KeyCtrl) { tab.Shpk.MaterialParams = tab.Shpk.MaterialParams.RemoveItems(idx); @@ -434,11 +435,11 @@ public partial class ModEditWindow } } - ImGuiUtil.HoverTooltip(tooltip); + ImUtf8.HoverTooltip(tooltip); } if (deletable) - ImGuiUtil.HoverTooltip("\nControl + Right-Click to remove."); + ImUtf8.HoverTooltip("\nControl + Right-Click to remove."u8); } } @@ -450,7 +451,9 @@ public partial class ModEditWindow if (!ImUtf8.Button("Export globally unused parameters as material dev-kit file"u8)) return; - tab.FileDialog.OpenSavePicker("Export material dev-kit file", ".json", $"{Path.GetFileNameWithoutExtension(tab.FilePath)}.json", ".json", DoSave, null, false); + tab.FileDialog.OpenSavePicker("Export material dev-kit file", ".json", $"{Path.GetFileNameWithoutExtension(tab.FilePath)}.json", + ".json", DoSave, null, false); + return; void DoSave(bool success, string path) { @@ -476,22 +479,22 @@ public partial class ModEditWindow private static void DrawShaderPackageMisalignedParameters(ShpkTab tab) { - using var t = ImRaii.TreeNode("Misaligned / Overflowing Parameters"); + using var t = ImUtf8.TreeNode("Misaligned / Overflowing Parameters"u8); if (!t) return; using var _ = ImRaii.PushFont(UiBuilder.MonoFont); foreach (var name in tab.MalformedParameters) - ImRaii.TreeNode(name, ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); + ImUtf8.TreeNode(name, ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); } private static void DrawShaderPackageStartCombo(ShpkTab tab) { using var s = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemInnerSpacing); - using (var _ = ImRaii.PushFont(UiBuilder.MonoFont)) + using (ImRaii.PushFont(UiBuilder.MonoFont)) { ImGui.SetNextItemWidth(UiHelpers.Scale * 400); - using var c = ImRaii.Combo("##Start", tab.Orphans[tab.NewMaterialParamStart].Name); + using var c = ImUtf8.Combo("##Start", tab.Orphans[tab.NewMaterialParamStart].Name); if (c) foreach (var (start, idx) in tab.Orphans.WithIndex()) { @@ -501,7 +504,7 @@ public partial class ModEditWindow } ImGui.SameLine(); - ImGui.TextUnformatted("Start"); + ImUtf8.Text("Start"u8); } private static void DrawShaderPackageEndCombo(ShpkTab tab) @@ -510,7 +513,7 @@ public partial class ModEditWindow using (var _ = ImRaii.PushFont(UiBuilder.MonoFont)) { ImGui.SetNextItemWidth(UiHelpers.Scale * 400); - using var c = ImRaii.Combo("##End", tab.Orphans[tab.NewMaterialParamEnd].Name); + using var c = ImUtf8.Combo("##End", tab.Orphans[tab.NewMaterialParamEnd].Name); if (c) { var current = tab.Orphans[tab.NewMaterialParamStart].Index; @@ -527,7 +530,7 @@ public partial class ModEditWindow } ImGui.SameLine(); - ImGui.TextUnformatted("End"); + ImUtf8.Text("End"u8); } private static bool DrawShaderPackageNewParameter(ShpkTab tab) @@ -540,15 +543,14 @@ public partial class ModEditWindow ImGui.SetNextItemWidth(UiHelpers.Scale * 400); var newName = tab.NewMaterialParamName.Value!; - if (ImGui.InputText("Name", ref newName, 63)) + if (ImUtf8.InputText("Name", ref newName)) tab.NewMaterialParamName = newName; var tooltip = tab.UsedIds.Contains(tab.NewMaterialParamName.Crc32) - ? "The ID is already in use. Please choose a different name." - : string.Empty; - if (!ImGuiUtil.DrawDisabledButton($"Add {tab.NewMaterialParamName} (0x{tab.NewMaterialParamName.Crc32:X8})", new Vector2(400 * UiHelpers.Scale, ImGui.GetFrameHeight()), - tooltip, - tooltip.Length > 0)) + ? "The ID is already in use. Please choose a different name."u8 + : ""u8; + if (!ImUtf8.ButtonEx($"Add {tab.NewMaterialParamName} (0x{tab.NewMaterialParamName.Crc32:X8})", tooltip, + new Vector2(400 * UiHelpers.Scale, ImGui.GetFrameHeight()), tooltip.Length > 0)) return false; tab.Shpk.MaterialParams = tab.Shpk.MaterialParams.AddItem(new MaterialParam @@ -589,15 +591,15 @@ public partial class ModEditWindow { var ret = false; - if (!ImGui.CollapsingHeader("Shader Resources")) + if (!ImUtf8.CollapsingHeader("Shader Resources"u8)) return false; var hasFilters = tab.FilterPopCount != tab.FilterMaximumPopCount; - ret |= DrawShaderPackageResourceArray("Constant Buffers", "type", true, tab.Shpk.Constants, hasFilters, disabled); - ret |= DrawShaderPackageResourceArray("Samplers", "type", false, tab.Shpk.Samplers, hasFilters, disabled); + ret |= DrawShaderPackageResourceArray("Constant Buffers", "type", true, tab.Shpk.Constants, hasFilters, disabled); + ret |= DrawShaderPackageResourceArray("Samplers", "type", false, tab.Shpk.Samplers, hasFilters, disabled); if (!tab.Shpk.IsLegacy) - ret |= DrawShaderPackageResourceArray("Textures", "type", false, tab.Shpk.Textures, hasFilters, disabled); - ret |= DrawShaderPackageResourceArray("Unordered Access Views", "type", false, tab.Shpk.Uavs, hasFilters, disabled); + ret |= DrawShaderPackageResourceArray("Textures", "type", false, tab.Shpk.Textures, hasFilters, disabled); + ret |= DrawShaderPackageResourceArray("Unordered Access Views", "type", false, tab.Shpk.Uavs, hasFilters, disabled); return ret; } @@ -607,18 +609,20 @@ public partial class ModEditWindow if (keys.Count == 0) return; - using var t = ImRaii.TreeNode(arrayName); + using var t = ImUtf8.TreeNode(arrayName); if (!t) return; using var font = ImRaii.PushFont(UiBuilder.MonoFont); foreach (var (key, idx) in keys.WithIndex()) { - using var t2 = ImRaii.TreeNode(withId ? $"#{idx}: {tab.TryResolveName(key.Id)} (0x{key.Id:X8})" : $"#{idx}"); + using var t2 = ImUtf8.TreeNode(withId ? $"#{idx}: {tab.TryResolveName(key.Id)} (0x{key.Id:X8})" : $"#{idx}"); if (t2) { - ImRaii.TreeNode($"Default Value: {tab.TryResolveName(key.DefaultValue)} (0x{key.DefaultValue:X8})", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); - ImRaii.TreeNode($"Known Values: {tab.NameSetToString(key.Values, true)}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); + ImUtf8.TreeNode($"Default Value: {tab.TryResolveName(key.DefaultValue)} (0x{key.DefaultValue:X8})", + ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); + ImUtf8.TreeNode($"Known Values: {tab.NameSetToString(key.Values, true)}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet) + .Dispose(); } } } @@ -628,7 +632,7 @@ public partial class ModEditWindow if (tab.Shpk.Nodes.Length <= 0) return; - using var t = ImRaii.TreeNode($"Nodes ({tab.Shpk.Nodes.Length})###Nodes"); + using var t = ImUtf8.TreeNode($"Nodes ({tab.Shpk.Nodes.Length})###Nodes"); if (!t) return; @@ -639,39 +643,44 @@ public partial class ModEditWindow if (!tab.IsFilterMatch(node)) continue; - using var t2 = ImRaii.TreeNode($"#{idx:D4}: Selector: 0x{node.Selector:X8}"); + using var t2 = ImUtf8.TreeNode($"#{idx:D4}: Selector: 0x{node.Selector:X8}"); if (!t2) continue; foreach (var (key, keyIdx) in node.SystemKeys.WithIndex()) { - ImRaii.TreeNode($"System Key {tab.TryResolveName(tab.Shpk.SystemKeys[keyIdx].Id)} = {tab.TryResolveName(key)} / \u2208 {{ {tab.NameSetToString(node.SystemValues![keyIdx])} }}", + ImUtf8.TreeNode( + $"System Key {tab.TryResolveName(tab.Shpk.SystemKeys[keyIdx].Id)} = {tab.TryResolveName(key)} / \u2208 {{ {tab.NameSetToString(node.SystemValues![keyIdx])} }}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); } foreach (var (key, keyIdx) in node.SceneKeys.WithIndex()) { - ImRaii.TreeNode($"Scene Key {tab.TryResolveName(tab.Shpk.SceneKeys[keyIdx].Id)} = {tab.TryResolveName(key)} / \u2208 {{ {tab.NameSetToString(node.SceneValues![keyIdx])} }}", + ImUtf8.TreeNode( + $"Scene Key {tab.TryResolveName(tab.Shpk.SceneKeys[keyIdx].Id)} = {tab.TryResolveName(key)} / \u2208 {{ {tab.NameSetToString(node.SceneValues![keyIdx])} }}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); } foreach (var (key, keyIdx) in node.MaterialKeys.WithIndex()) { - ImRaii.TreeNode($"Material Key {tab.TryResolveName(tab.Shpk.MaterialKeys[keyIdx].Id)} = {tab.TryResolveName(key)} / \u2208 {{ {tab.NameSetToString(node.MaterialValues![keyIdx])} }}", + ImUtf8.TreeNode( + $"Material Key {tab.TryResolveName(tab.Shpk.MaterialKeys[keyIdx].Id)} = {tab.TryResolveName(key)} / \u2208 {{ {tab.NameSetToString(node.MaterialValues![keyIdx])} }}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); } foreach (var (key, keyIdx) in node.SubViewKeys.WithIndex()) { - ImRaii.TreeNode($"Sub-View Key #{keyIdx} = {tab.TryResolveName(key)} / \u2208 {{ {tab.NameSetToString(node.SubViewValues![keyIdx])} }}", + ImUtf8.TreeNode( + $"Sub-View Key #{keyIdx} = {tab.TryResolveName(key)} / \u2208 {{ {tab.NameSetToString(node.SubViewValues![keyIdx])} }}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); } - ImRaii.TreeNode($"Pass Indices: {string.Join(' ', node.PassIndices.Select(c => $"{c:X2}"))}", + ImUtf8.TreeNode($"Pass Indices: {string.Join(' ', node.PassIndices.Select(c => $"{c:X2}"))}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); foreach (var (pass, passIdx) in node.Passes.WithIndex()) { - ImRaii.TreeNode($"Pass #{passIdx}: ID: {tab.TryResolveName(pass.Id)}, Vertex Shader #{pass.VertexShader}, Pixel Shader #{pass.PixelShader}", + ImUtf8.TreeNode( + $"Pass #{passIdx}: ID: {tab.TryResolveName(pass.Id)}, Vertex Shader #{pass.VertexShader}, Pixel Shader #{pass.PixelShader}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet) .Dispose(); } @@ -680,7 +689,7 @@ public partial class ModEditWindow private static void DrawShaderPackageSelection(ShpkTab tab) { - if (!ImGui.CollapsingHeader("Shader Selection")) + if (!ImUtf8.CollapsingHeader("Shader Selection"u8)) return; DrawKeyArray(tab, "System Keys", true, tab.Shpk.SystemKeys); @@ -689,13 +698,13 @@ public partial class ModEditWindow DrawKeyArray(tab, "Sub-View Keys", false, tab.Shpk.SubViewKeys); DrawShaderPackageNodes(tab); - using var t = ImRaii.TreeNode($"Node Selectors ({tab.Shpk.NodeSelectors.Count})###NodeSelectors"); + using var t = ImUtf8.TreeNode($"Node Selectors ({tab.Shpk.NodeSelectors.Count})###NodeSelectors"); if (t) { using var font = ImRaii.PushFont(UiBuilder.MonoFont); foreach (var selector in tab.Shpk.NodeSelectors) { - ImRaii.TreeNode($"#{selector.Value:D4}: Selector: 0x{selector.Key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet) + ImUtf8.TreeNode($"#{selector.Value:D4}: Selector: 0x{selector.Key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet) .Dispose(); } } @@ -703,14 +712,14 @@ public partial class ModEditWindow private static void DrawOtherShaderPackageDetails(ShpkTab tab) { - if (!ImGui.CollapsingHeader("Further Content")) + if (!ImUtf8.CollapsingHeader("Further Content"u8)) return; - ImRaii.TreeNode($"Version: 0x{tab.Shpk.Version:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); + ImUtf8.TreeNode($"Version: 0x{tab.Shpk.Version:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); if (tab.Shpk.AdditionalData.Length > 0) { - using var t = ImRaii.TreeNode($"Additional Data (Size: {tab.Shpk.AdditionalData.Length})###AdditionalData"); + using var t = ImUtf8.TreeNode($"Additional Data (Size: {tab.Shpk.AdditionalData.Length})###AdditionalData"); if (t) Widget.DrawHexViewer(tab.Shpk.AdditionalData); } @@ -718,9 +727,9 @@ public partial class ModEditWindow private static string UsedComponentString(bool withSize, bool filtered, in Resource resource) { - var used = filtered ? resource.FilteredUsed : resource.Used; + var used = filtered ? resource.FilteredUsed : resource.Used; var usedDynamically = filtered ? resource.FilteredUsedDynamically : resource.UsedDynamically; - var sb = new StringBuilder(256); + var sb = new StringBuilder(256); if (withSize) { foreach (var (components, i) in (used ?? Array.Empty()).WithIndex()) diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.ShpkTab.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.ShpkTab.cs index de20aa9f..b5b39e90 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.ShpkTab.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.ShpkTab.cs @@ -21,11 +21,11 @@ public partial class ModEditWindow public short NewMaterialParamStart; public short NewMaterialParamEnd; - public SharedSet[] FilterSystemValues; - public SharedSet[] FilterSceneValues; - public SharedSet[] FilterMaterialValues; - public SharedSet[] FilterSubViewValues; - public SharedSet FilterPasses; + public readonly SharedSet[] FilterSystemValues; + public readonly SharedSet[] FilterSceneValues; + public readonly SharedSet[] FilterMaterialValues; + public readonly SharedSet[] FilterSubViewValues; + public SharedSet FilterPasses; public readonly int FilterMaximumPopCount; public int FilterPopCount; @@ -46,6 +46,7 @@ public partial class ModEditWindow { Shpk = new ShpkFile(bytes, false); } + FilePath = filePath; Header = $"Shader Package for DirectX {(int)Shpk.DirectXVersion}"; @@ -105,13 +106,21 @@ public partial class ModEditWindow _nameSetWithIdsCache.Clear(); } - public void UpdateNameCache() + private void UpdateNameCache() { - static void CollectResourceNames(Dictionary nameCache, ShpkFile.Resource[] resources) - { - foreach (var resource in resources) - nameCache.TryAdd(resource.Id, resource.Name); - } + CollectResourceNames(_nameCache, Shpk.Constants); + CollectResourceNames(_nameCache, Shpk.Samplers); + CollectResourceNames(_nameCache, Shpk.Textures); + CollectResourceNames(_nameCache, Shpk.Uavs); + + CollectKeyNames(_nameCache, Shpk.SystemKeys); + CollectKeyNames(_nameCache, Shpk.SceneKeys); + CollectKeyNames(_nameCache, Shpk.MaterialKeys); + CollectKeyNames(_nameCache, Shpk.SubViewKeys); + + _nameSetCache.Clear(); + _nameSetWithIdsCache.Clear(); + return; static void CollectKeyNames(Dictionary nameCache, ShpkFile.Key[] keys) { @@ -128,18 +137,11 @@ public partial class ModEditWindow } } - CollectResourceNames(_nameCache, Shpk.Constants); - CollectResourceNames(_nameCache, Shpk.Samplers); - CollectResourceNames(_nameCache, Shpk.Textures); - CollectResourceNames(_nameCache, Shpk.Uavs); - - CollectKeyNames(_nameCache, Shpk.SystemKeys); - CollectKeyNames(_nameCache, Shpk.SceneKeys); - CollectKeyNames(_nameCache, Shpk.MaterialKeys); - CollectKeyNames(_nameCache, Shpk.SubViewKeys); - - _nameSetCache.Clear(); - _nameSetWithIdsCache.Clear(); + static void CollectResourceNames(Dictionary nameCache, ShpkFile.Resource[] resources) + { + foreach (var resource in resources) + nameCache.TryAdd(resource.Id, resource.Name); + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -151,6 +153,7 @@ public partial class ModEditWindow var cache = withIds ? _nameSetWithIdsCache : _nameSetCache; if (cache.TryGetValue(nameSet, out var nameSetStr)) return nameSetStr; + if (withIds) nameSetStr = string.Join(", ", nameSet.Select(id => $"{TryResolveName(id)} (0x{id:X8})")); else @@ -186,7 +189,8 @@ public partial class ModEditWindow var jEnd = ((param.ByteOffset + param.ByteSize - 1) >> 2) & 3; if ((param.ByteOffset & 0x3) != 0 || (param.ByteSize & 0x3) != 0) { - MalformedParameters.Add($"ID: {TryResolveName(param.Id)} (0x{param.Id:X8}), offset: 0x{param.ByteOffset:X4}, size: 0x{param.ByteSize:X4}"); + MalformedParameters.Add( + $"ID: {TryResolveName(param.Id)} (0x{param.Id:X8}), offset: 0x{param.ByteOffset:X4}, size: 0x{param.ByteSize:X4}"); continue; } @@ -206,7 +210,8 @@ public partial class ModEditWindow var tt = $"{MtrlTab.MaterialParamRangeName(materialParams?.Name ?? string.Empty, param.ByteOffset >> 2, param.ByteSize >> 2).Item1} ({TryResolveName(param.Id)}, 0x{param.Id:X8})"; if (component < defaultFloats.Length) - tt += $"\n\nDefault value: {defaultFloats[component]} ({defaults[component << 2]:X2} {defaults[(component << 2) | 1]:X2} {defaults[(component << 2) | 2]:X2} {defaults[(component << 2) | 3]:X2})"; + tt += + $"\n\nDefault value: {defaultFloats[component]} ({defaults[component << 2]:X2} {defaults[(component << 2) | 1]:X2} {defaults[(component << 2) | 2]:X2} {defaults[(component << 2) | 3]:X2})"; Matrix[i, j] = (TryResolveName(param.Id).ToString(), tt, (short)idx, 0); } } @@ -265,7 +270,8 @@ public partial class ModEditWindow if (oldStart == linear) newMaterialParamStart = (short)Orphans.Count; - Orphans.Add(($"{materialParams?.Name ?? ShpkFile.MaterialParamsConstantName}{MtrlTab.MaterialParamName(false, linear)}", linear)); + Orphans.Add(($"{materialParams?.Name ?? ShpkFile.MaterialParamsConstantName}{MtrlTab.MaterialParamName(false, linear)}", + linear)); } } @@ -407,7 +413,6 @@ public partial class ModEditWindow var unusedSlices = new JArray(); if (materialParameterUsage.Indices(start, length).Any()) - { foreach (var (rgStart, rgEnd) in materialParameterUsage.Ranges(start, length, true)) { unusedSlices.Add(new JObject @@ -417,14 +422,11 @@ public partial class ModEditWindow ["Length"] = rgEnd - rgStart, }); } - } else - { unusedSlices.Add(new JObject { ["Type"] = "Hidden", }); - } dkConstants[param.Id.ToString()] = unusedSlices; }