Auto-formatting and some cleanup.

This commit is contained in:
Ottermandias 2023-08-31 17:12:39 +02:00
parent ff01276869
commit e5e555b981
8 changed files with 876 additions and 959 deletions

View file

@ -20,15 +20,11 @@ public partial class ModEditWindow
private bool DrawMaterialColorSetChange(MtrlTab tab, bool disabled) private bool DrawMaterialColorSetChange(MtrlTab tab, bool disabled)
{ {
if (!tab.SamplerIds.Contains(ShpkFile.TableSamplerId) || !tab.Mtrl.ColorSets.Any(c => c.HasRows)) if (!tab.SamplerIds.Contains(ShpkFile.TableSamplerId) || !tab.Mtrl.ColorSets.Any(c => c.HasRows))
{
return false; return false;
}
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2)); ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
if (!ImGui.CollapsingHeader("Color Set", ImGuiTreeNodeFlags.DefaultOpen)) if (!ImGui.CollapsingHeader("Color Set", ImGuiTreeNodeFlags.DefaultOpen))
{
return false; return false;
}
var hasAnyDye = tab.UseColorDyeSet; var hasAnyDye = tab.UseColorDyeSet;
@ -42,6 +38,7 @@ public partial class ModEditWindow
ImGui.SameLine(); ImGui.SameLine();
ret |= ColorSetDyeableCheckbox(tab, ref hasAnyDye); ret |= ColorSetDyeableCheckbox(tab, ref hasAnyDye);
} }
if (hasAnyDye) if (hasAnyDye)
{ {
ImGui.SameLine(); ImGui.SameLine();
@ -53,9 +50,7 @@ public partial class ModEditWindow
using var table = ImRaii.Table("##ColorSets", hasAnyDye ? 11 : 9, using var table = ImRaii.Table("##ColorSets", hasAnyDye ? 11 : 9,
ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg | ImGuiTableFlags.BordersInnerV); ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg | ImGuiTableFlags.BordersInnerV);
if (!table) if (!table)
{
return false; return false;
}
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.TableHeader(string.Empty); ImGui.TableHeader(string.Empty);
@ -100,9 +95,7 @@ public partial class ModEditWindow
private static void ColorSetCopyAllClipboardButton(MtrlFile file, int colorSetIdx) private static void ColorSetCopyAllClipboardButton(MtrlFile file, int colorSetIdx)
{ {
if (!ImGui.Button("Export All Rows to Clipboard", ImGuiHelpers.ScaledVector2(200, 0))) if (!ImGui.Button("Export All Rows to Clipboard", ImGuiHelpers.ScaledVector2(200, 0)))
{
return; return;
}
try try
{ {
@ -123,17 +116,17 @@ public partial class ModEditWindow
private bool DrawPreviewDye(MtrlTab tab, bool disabled) private bool DrawPreviewDye(MtrlTab tab, bool disabled)
{ {
var (dyeId, (name, dyeColor, gloss)) = _stainService.StainCombo.CurrentSelection; var (dyeId, (name, dyeColor, gloss)) = _stainService.StainCombo.CurrentSelection;
var tt = dyeId == 0 ? "Select a preview dye first." : "Apply all preview values corresponding to the dye template and chosen dye where dyeing is enabled."; var tt = dyeId == 0
? "Select a preview dye first."
: "Apply all preview values corresponding to the dye template and chosen dye where dyeing is enabled.";
if (ImGuiUtil.DrawDisabledButton("Apply Preview Dye", Vector2.Zero, tt, disabled || dyeId == 0)) if (ImGuiUtil.DrawDisabledButton("Apply Preview Dye", Vector2.Zero, tt, disabled || dyeId == 0))
{ {
var ret = false; var ret = false;
for (var j = 0; j < tab.Mtrl.ColorDyeSets.Length; ++j) for (var j = 0; j < tab.Mtrl.ColorDyeSets.Length; ++j)
{ {
for (var i = 0; i < MtrlFile.ColorSet.RowArray.NumRows; ++i) for (var i = 0; i < MtrlFile.ColorSet.RowArray.NumRows; ++i)
{
ret |= tab.Mtrl.ApplyDyeTemplate(_stainService.StmFile, j, i, dyeId); ret |= tab.Mtrl.ApplyDyeTemplate(_stainService.StmFile, j, i, dyeId);
} }
}
tab.UpdateColorSetPreview(); tab.UpdateColorSetPreview();
@ -149,19 +142,16 @@ public partial class ModEditWindow
private static unsafe bool ColorSetPasteAllClipboardButton(MtrlTab tab, int colorSetIdx, bool disabled) private static unsafe bool ColorSetPasteAllClipboardButton(MtrlTab tab, int colorSetIdx, bool disabled)
{ {
if( !ImGuiUtil.DrawDisabledButton( "Import All Rows from Clipboard", ImGuiHelpers.ScaledVector2( 200, 0 ), string.Empty, disabled ) || tab.Mtrl.ColorSets.Length <= colorSetIdx ) if (!ImGuiUtil.DrawDisabledButton("Import All Rows from Clipboard", ImGuiHelpers.ScaledVector2(200, 0), string.Empty, disabled)
{ || tab.Mtrl.ColorSets.Length <= colorSetIdx)
return false; return false;
}
try try
{ {
var text = ImGui.GetClipboardText(); var text = ImGui.GetClipboardText();
var data = Convert.FromBase64String(text); var data = Convert.FromBase64String(text);
if (data.Length < Marshal.SizeOf<MtrlFile.ColorSet.RowArray>()) if (data.Length < Marshal.SizeOf<MtrlFile.ColorSet.RowArray>())
{
return false; return false;
}
ref var rows = ref tab.Mtrl.ColorSets[colorSetIdx].Rows; ref var rows = ref tab.Mtrl.ColorSets[colorSetIdx].Rows;
fixed (void* ptr = data, output = &rows) fixed (void* ptr = data, output = &rows)
@ -173,7 +163,8 @@ public partial class ModEditWindow
ref var dyeRows = ref tab.Mtrl.ColorDyeSets[colorSetIdx].Rows; ref var dyeRows = ref tab.Mtrl.ColorDyeSets[colorSetIdx].Rows;
fixed (void* output2 = &dyeRows) fixed (void* output2 = &dyeRows)
{ {
MemoryUtility.MemCpyUnchecked( output2, ( byte* )ptr + Marshal.SizeOf< MtrlFile.ColorSet.RowArray >(), Marshal.SizeOf< MtrlFile.ColorDyeSet.RowArray >() ); MemoryUtility.MemCpyUnchecked(output2, (byte*)ptr + Marshal.SizeOf<MtrlFile.ColorSet.RowArray>(),
Marshal.SizeOf<MtrlFile.ColorDyeSet.RowArray>());
} }
} }
} }
@ -190,9 +181,10 @@ public partial class ModEditWindow
private static unsafe void ColorSetCopyClipboardButton(MtrlFile.ColorSet.Row row, MtrlFile.ColorDyeSet.Row dye) private static unsafe void ColorSetCopyClipboardButton(MtrlFile.ColorSet.Row row, MtrlFile.ColorDyeSet.Row dye)
{ {
if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Clipboard.ToIconString(), ImGui.GetFrameHeight() * Vector2.One, if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Clipboard.ToIconString(), ImGui.GetFrameHeight() * Vector2.One,
"Export this row to your clipboard.", false, true)) "Export this row to your clipboard.", false, true))
{ return;
try try
{ {
var data = new byte[MtrlFile.ColorSet.Row.Size + 2]; var data = new byte[MtrlFile.ColorSet.Row.Size + 2];
@ -210,7 +202,6 @@ public partial class ModEditWindow
// ignored // ignored
} }
} }
}
private static bool ColorSetDyeableCheckbox(MtrlTab tab, ref bool dyeable) private static bool ColorSetDyeableCheckbox(MtrlTab tab, ref bool dyeable)
{ {
@ -229,27 +220,24 @@ public partial class ModEditWindow
private static unsafe bool ColorSetPasteFromClipboardButton(MtrlTab tab, int colorSetIdx, int rowIdx, bool disabled) private static unsafe bool ColorSetPasteFromClipboardButton(MtrlTab tab, int colorSetIdx, int rowIdx, bool disabled)
{ {
if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Paste.ToIconString(), ImGui.GetFrameHeight() * Vector2.One, if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Paste.ToIconString(), ImGui.GetFrameHeight() * Vector2.One,
"Import an exported row from your clipboard onto this row.", disabled, true)) "Import an exported row from your clipboard onto this row.", disabled, true))
{ return false;
try try
{ {
var text = ImGui.GetClipboardText(); var text = ImGui.GetClipboardText();
var data = Convert.FromBase64String(text); var data = Convert.FromBase64String(text);
if (data.Length != MtrlFile.ColorSet.Row.Size + 2 if (data.Length != MtrlFile.ColorSet.Row.Size + 2
|| tab.Mtrl.ColorSets.Length <= colorSetIdx) || tab.Mtrl.ColorSets.Length <= colorSetIdx)
{
return false; return false;
}
fixed (byte* ptr = data) fixed (byte* ptr = data)
{ {
tab.Mtrl.ColorSets[colorSetIdx].Rows[rowIdx] = *(MtrlFile.ColorSet.Row*)ptr; tab.Mtrl.ColorSets[colorSetIdx].Rows[rowIdx] = *(MtrlFile.ColorSet.Row*)ptr;
if (colorSetIdx < tab.Mtrl.ColorDyeSets.Length) if (colorSetIdx < tab.Mtrl.ColorDyeSets.Length)
{
tab.Mtrl.ColorDyeSets[colorSetIdx].Rows[rowIdx] = *(MtrlFile.ColorDyeSet.Row*)(ptr + MtrlFile.ColorSet.Row.Size); tab.Mtrl.ColorDyeSets[colorSetIdx].Rows[rowIdx] = *(MtrlFile.ColorDyeSet.Row*)(ptr + MtrlFile.ColorSet.Row.Size);
} }
}
tab.UpdateColorSetRowPreview(rowIdx); tab.UpdateColorSetRowPreview(rowIdx);
@ -257,12 +245,9 @@ public partial class ModEditWindow
} }
catch catch
{ {
// ignored
}
}
return false; return false;
} }
}
private static void ColorSetHighlightButton(MtrlTab tab, int rowIdx, bool disabled) private static void ColorSetHighlightButton(MtrlTab tab, int rowIdx, bool disabled)
{ {
@ -301,16 +286,28 @@ public partial class ModEditWindow
ImGui.TableNextColumn(); ImGui.TableNextColumn();
using var dis = ImRaii.Disabled(disabled); using var dis = ImRaii.Disabled(disabled);
ret |= ColorPicker( "##Diffuse", "Diffuse Color", row.Diffuse, c => { tab.Mtrl.ColorSets[ colorSetIdx ].Rows[ rowIdx ].Diffuse = c; tab.UpdateColorSetRowPreview(rowIdx); } ); ret |= ColorPicker("##Diffuse", "Diffuse Color", row.Diffuse, c =>
{
tab.Mtrl.ColorSets[colorSetIdx].Rows[rowIdx].Diffuse = c;
tab.UpdateColorSetRowPreview(rowIdx);
});
if (hasDye) if (hasDye)
{ {
ImGui.SameLine(); ImGui.SameLine();
ret |= ImGuiUtil.Checkbox("##dyeDiffuse", "Apply Diffuse Color on Dye", dye.Diffuse, ret |= ImGuiUtil.Checkbox("##dyeDiffuse", "Apply Diffuse Color on Dye", dye.Diffuse,
b => { tab.Mtrl.ColorDyeSets[ colorSetIdx ].Rows[ rowIdx ].Diffuse = b; tab.UpdateColorSetRowPreview(rowIdx); }, ImGuiHoveredFlags.AllowWhenDisabled ); b =>
{
tab.Mtrl.ColorDyeSets[colorSetIdx].Rows[rowIdx].Diffuse = b;
tab.UpdateColorSetRowPreview(rowIdx);
}, ImGuiHoveredFlags.AllowWhenDisabled);
} }
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ret |= ColorPicker( "##Specular", "Specular Color", row.Specular, c => { tab.Mtrl.ColorSets[ colorSetIdx ].Rows[ rowIdx ].Specular = c; tab.UpdateColorSetRowPreview(rowIdx); } ); ret |= ColorPicker("##Specular", "Specular Color", row.Specular, c =>
{
tab.Mtrl.ColorSets[colorSetIdx].Rows[rowIdx].Specular = c;
tab.UpdateColorSetRowPreview(rowIdx);
});
ImGui.SameLine(); ImGui.SameLine();
var tmpFloat = row.SpecularStrength; var tmpFloat = row.SpecularStrength;
ImGui.SetNextItemWidth(floatSize); ImGui.SetNextItemWidth(floatSize);
@ -327,25 +324,42 @@ public partial class ModEditWindow
{ {
ImGui.SameLine(); ImGui.SameLine();
ret |= ImGuiUtil.Checkbox("##dyeSpecular", "Apply Specular Color on Dye", dye.Specular, ret |= ImGuiUtil.Checkbox("##dyeSpecular", "Apply Specular Color on Dye", dye.Specular,
b => { tab.Mtrl.ColorDyeSets[ colorSetIdx ].Rows[ rowIdx ].Specular = b; tab.UpdateColorSetRowPreview(rowIdx); }, ImGuiHoveredFlags.AllowWhenDisabled ); b =>
{
tab.Mtrl.ColorDyeSets[colorSetIdx].Rows[rowIdx].Specular = b;
tab.UpdateColorSetRowPreview(rowIdx);
}, ImGuiHoveredFlags.AllowWhenDisabled);
ImGui.SameLine(); ImGui.SameLine();
ret |= ImGuiUtil.Checkbox("##dyeSpecularStrength", "Apply Specular Strength on Dye", dye.SpecularStrength, ret |= ImGuiUtil.Checkbox("##dyeSpecularStrength", "Apply Specular Strength on Dye", dye.SpecularStrength,
b => { tab.Mtrl.ColorDyeSets[ colorSetIdx ].Rows[ rowIdx ].SpecularStrength = b; tab.UpdateColorSetRowPreview(rowIdx); }, ImGuiHoveredFlags.AllowWhenDisabled ); b =>
{
tab.Mtrl.ColorDyeSets[colorSetIdx].Rows[rowIdx].SpecularStrength = b;
tab.UpdateColorSetRowPreview(rowIdx);
}, ImGuiHoveredFlags.AllowWhenDisabled);
} }
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ret |= ColorPicker( "##Emissive", "Emissive Color", row.Emissive, c => { tab.Mtrl.ColorSets[ colorSetIdx ].Rows[ rowIdx ].Emissive = c; tab.UpdateColorSetRowPreview(rowIdx); } ); ret |= ColorPicker("##Emissive", "Emissive Color", row.Emissive, c =>
{
tab.Mtrl.ColorSets[colorSetIdx].Rows[rowIdx].Emissive = c;
tab.UpdateColorSetRowPreview(rowIdx);
});
if (hasDye) if (hasDye)
{ {
ImGui.SameLine(); ImGui.SameLine();
ret |= ImGuiUtil.Checkbox("##dyeEmissive", "Apply Emissive Color on Dye", dye.Emissive, ret |= ImGuiUtil.Checkbox("##dyeEmissive", "Apply Emissive Color on Dye", dye.Emissive,
b => { tab.Mtrl.ColorDyeSets[ colorSetIdx ].Rows[ rowIdx ].Emissive = b; tab.UpdateColorSetRowPreview(rowIdx); }, ImGuiHoveredFlags.AllowWhenDisabled ); b =>
{
tab.Mtrl.ColorDyeSets[colorSetIdx].Rows[rowIdx].Emissive = b;
tab.UpdateColorSetRowPreview(rowIdx);
}, ImGuiHoveredFlags.AllowWhenDisabled);
} }
ImGui.TableNextColumn(); ImGui.TableNextColumn();
tmpFloat = row.GlossStrength; tmpFloat = row.GlossStrength;
ImGui.SetNextItemWidth(floatSize); ImGui.SetNextItemWidth(floatSize);
if( ImGui.DragFloat( "##GlossStrength", ref tmpFloat, Math.Max( 0.1f, tmpFloat * 0.025f ), HalfEpsilon, HalfMaxValue, "%.1f" ) && FixFloat( ref tmpFloat, row.GlossStrength ) ) if (ImGui.DragFloat("##GlossStrength", ref tmpFloat, Math.Max(0.1f, tmpFloat * 0.025f), HalfEpsilon, HalfMaxValue, "%.1f")
&& FixFloat(ref tmpFloat, row.GlossStrength))
{ {
tab.Mtrl.ColorSets[colorSetIdx].Rows[rowIdx].GlossStrength = Math.Max(tmpFloat, HalfEpsilon); tab.Mtrl.ColorSets[colorSetIdx].Rows[rowIdx].GlossStrength = Math.Max(tmpFloat, HalfEpsilon);
ret = true; ret = true;
@ -357,7 +371,11 @@ public partial class ModEditWindow
{ {
ImGui.SameLine(); ImGui.SameLine();
ret |= ImGuiUtil.Checkbox("##dyeGloss", "Apply Gloss Strength on Dye", dye.Gloss, ret |= ImGuiUtil.Checkbox("##dyeGloss", "Apply Gloss Strength on Dye", dye.Gloss,
b => { tab.Mtrl.ColorDyeSets[ colorSetIdx ].Rows[ rowIdx ].Gloss = b; tab.UpdateColorSetRowPreview(rowIdx); }, ImGuiHoveredFlags.AllowWhenDisabled ); b =>
{
tab.Mtrl.ColorDyeSets[colorSetIdx].Rows[rowIdx].Gloss = b;
tab.UpdateColorSetRowPreview(rowIdx);
}, ImGuiHoveredFlags.AllowWhenDisabled);
} }
ImGui.TableNextColumn(); ImGui.TableNextColumn();
@ -375,7 +393,8 @@ public partial class ModEditWindow
ImGui.TableNextColumn(); ImGui.TableNextColumn();
tmpFloat = row.MaterialRepeat.X; tmpFloat = row.MaterialRepeat.X;
ImGui.SetNextItemWidth(floatSize); ImGui.SetNextItemWidth(floatSize);
if( ImGui.DragFloat( "##RepeatX", ref tmpFloat, 0.1f, HalfMinValue, HalfMaxValue, "%.2f" ) && FixFloat( ref tmpFloat, row.MaterialRepeat.X ) ) if (ImGui.DragFloat("##RepeatX", ref tmpFloat, 0.1f, HalfMinValue, HalfMaxValue, "%.2f")
&& FixFloat(ref tmpFloat, row.MaterialRepeat.X))
{ {
tab.Mtrl.ColorSets[colorSetIdx].Rows[rowIdx].MaterialRepeat = row.MaterialRepeat with { X = tmpFloat }; tab.Mtrl.ColorSets[colorSetIdx].Rows[rowIdx].MaterialRepeat = row.MaterialRepeat with { X = tmpFloat };
ret = true; ret = true;
@ -386,7 +405,8 @@ public partial class ModEditWindow
ImGui.SameLine(); ImGui.SameLine();
tmpFloat = row.MaterialRepeat.Y; tmpFloat = row.MaterialRepeat.Y;
ImGui.SetNextItemWidth(floatSize); ImGui.SetNextItemWidth(floatSize);
if( ImGui.DragFloat( "##RepeatY", ref tmpFloat, 0.1f, HalfMinValue, HalfMaxValue, "%.2f" ) && FixFloat( ref tmpFloat, row.MaterialRepeat.Y ) ) if (ImGui.DragFloat("##RepeatY", ref tmpFloat, 0.1f, HalfMinValue, HalfMaxValue, "%.2f")
&& FixFloat(ref tmpFloat, row.MaterialRepeat.Y))
{ {
tab.Mtrl.ColorSets[colorSetIdx].Rows[rowIdx].MaterialRepeat = row.MaterialRepeat with { Y = tmpFloat }; tab.Mtrl.ColorSets[colorSetIdx].Rows[rowIdx].MaterialRepeat = row.MaterialRepeat with { Y = tmpFloat };
ret = true; ret = true;
@ -449,9 +469,7 @@ public partial class ModEditWindow
{ {
var stain = _stainService.StainCombo.CurrentSelection.Key; var stain = _stainService.StainCombo.CurrentSelection.Key;
if (stain == 0 || !_stainService.StmFile.Entries.TryGetValue(dye.Template, out var entry)) if (stain == 0 || !_stainService.StmFile.Entries.TryGetValue(dye.Template, out var entry))
{
return false; return false;
}
var values = entry[(int)stain]; var values = entry[(int)stain];
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemSpacing / 2); using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemSpacing / 2);
@ -486,7 +504,11 @@ public partial class ModEditWindow
var inputSqrt = PseudoSqrtRgb(input); var inputSqrt = PseudoSqrtRgb(input);
var tmp = inputSqrt; var tmp = inputSqrt;
if (ImGui.ColorEdit3(label, ref tmp, if (ImGui.ColorEdit3(label, ref tmp,
ImGuiColorEditFlags.NoInputs | ImGuiColorEditFlags.DisplayRGB | ImGuiColorEditFlags.InputRGB | ImGuiColorEditFlags.NoTooltip | ImGuiColorEditFlags.HDR ) ImGuiColorEditFlags.NoInputs
| ImGuiColorEditFlags.DisplayRGB
| ImGuiColorEditFlags.InputRGB
| ImGuiColorEditFlags.NoTooltip
| ImGuiColorEditFlags.HDR)
&& tmp != inputSqrt) && tmp != inputSqrt)
{ {
setter(PseudoSquareRgb(tmp)); setter(PseudoSquareRgb(tmp));
@ -509,7 +531,7 @@ public partial class ModEditWindow
// Functions to deal with squared RGB values without making negatives useless. // Functions to deal with squared RGB values without making negatives useless.
private static float PseudoSquareRgb(float x) private static float PseudoSquareRgb(float x)
=> x < 0.0f ? -(x * x) : (x * x); => x < 0.0f ? -(x * x) : x * x;
private static Vector3 PseudoSquareRgb(Vector3 vec) private static Vector3 PseudoSquareRgb(Vector3 vec)
=> new(PseudoSquareRgb(vec.X), PseudoSquareRgb(vec.Y), PseudoSquareRgb(vec.Z)); => new(PseudoSquareRgb(vec.X), PseudoSquareRgb(vec.Y), PseudoSquareRgb(vec.Z));

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Numerics; using System.Numerics;
using ImGuiNET; using ImGuiNET;
using OtterGui.Raii; using OtterGui.Raii;
@ -27,7 +28,8 @@ public partial class ModEditWindow
private readonly float _bias; private readonly float _bias;
private readonly string _format; private readonly string _format;
public FloatConstantEditor(float? minimum, float? maximum, float speed, float relativeSpeed, float factor, float bias, byte precision, string unit) public FloatConstantEditor(float? minimum, float? maximum, float speed, float relativeSpeed, float factor, float bias, byte precision,
string unit)
{ {
_minimum = minimum; _minimum = minimum;
_maximum = maximum; _maximum = maximum;
@ -55,10 +57,13 @@ public partial class ModEditWindow
var value = (values[valueIdx] - _bias) / _factor; var value = (values[valueIdx] - _bias) / _factor;
if (disabled) if (disabled)
{
ImGui.DragFloat($"##{valueIdx}", ref value, Math.Max(_speed, value * _relativeSpeed), value, value, _format); ImGui.DragFloat($"##{valueIdx}", ref value, Math.Max(_speed, value * _relativeSpeed), value, value, _format);
}
else else
{ {
if (ImGui.DragFloat($"##{valueIdx}", ref value, Math.Max(_speed, value * _relativeSpeed), _minimum ?? 0.0f, _maximum ?? 0.0f, _format)) if (ImGui.DragFloat($"##{valueIdx}", ref value, Math.Max(_speed, value * _relativeSpeed), _minimum ?? 0.0f,
_maximum ?? 0.0f, _format))
{ {
values[valueIdx] = Clamp(value) * _factor + _bias; values[valueIdx] = Clamp(value) * _factor + _bias;
ret = true; ret = true;
@ -111,10 +116,13 @@ public partial class ModEditWindow
var value = (int)Math.Clamp(MathF.Round((values[valueIdx] - _bias) / _factor), int.MinValue, int.MaxValue); var value = (int)Math.Clamp(MathF.Round((values[valueIdx] - _bias) / _factor), int.MinValue, int.MaxValue);
if (disabled) if (disabled)
{
ImGui.DragInt($"##{valueIdx}", ref value, Math.Max(_speed, value * _relativeSpeed), value, value, _format); ImGui.DragInt($"##{valueIdx}", ref value, Math.Max(_speed, value * _relativeSpeed), value, value, _format);
}
else else
{ {
if (ImGui.DragInt($"##{valueIdx}", ref value, Math.Max(_speed, value * _relativeSpeed), _minimum ?? 0, _maximum ?? 0, _format)) if (ImGui.DragInt($"##{valueIdx}", ref value, Math.Max(_speed, value * _relativeSpeed), _minimum ?? 0, _maximum ?? 0,
_format))
{ {
values[valueIdx] = Clamp(value) * _factor + _bias; values[valueIdx] = Clamp(value) * _factor + _bias;
ret = true; ret = true;
@ -142,14 +150,17 @@ public partial class ModEditWindow
public bool Draw(Span<float> values, bool disabled, float editorWidth) public bool Draw(Span<float> values, bool disabled, float editorWidth)
{ {
if (values.Length == 3) switch (values.Length)
{
case 3:
{ {
ImGui.SetNextItemWidth(editorWidth); ImGui.SetNextItemWidth(editorWidth);
var value = new Vector3(values); var value = new Vector3(values);
if (_squaredRgb) if (_squaredRgb)
value = PseudoSqrtRgb(value); value = PseudoSqrtRgb(value);
if (ImGui.ColorEdit3("##0", ref value, ImGuiColorEditFlags.Float | (_clamped ? 0 : ImGuiColorEditFlags.HDR)) && !disabled) if (!ImGui.ColorEdit3("##0", ref value, ImGuiColorEditFlags.Float | (_clamped ? 0 : ImGuiColorEditFlags.HDR)) || disabled)
{ return false;
if (_squaredRgb) if (_squaredRgb)
value = PseudoSquareRgb(value); value = PseudoSquareRgb(value);
if (_clamped) if (_clamped)
@ -157,17 +168,17 @@ public partial class ModEditWindow
value.CopyTo(values); value.CopyTo(values);
return true; return true;
} }
case 4:
return false;
}
else if (values.Length == 4)
{ {
ImGui.SetNextItemWidth(editorWidth); ImGui.SetNextItemWidth(editorWidth);
var value = new Vector4(values); var value = new Vector4(values);
if (_squaredRgb) if (_squaredRgb)
value = PseudoSqrtRgb(value); value = PseudoSqrtRgb(value);
if (ImGui.ColorEdit4("##0", ref value, ImGuiColorEditFlags.Float | ImGuiColorEditFlags.AlphaPreviewHalf | (_clamped ? 0 : ImGuiColorEditFlags.HDR)) && !disabled) if (!ImGui.ColorEdit4("##0", ref value,
{ ImGuiColorEditFlags.Float | ImGuiColorEditFlags.AlphaPreviewHalf | (_clamped ? 0 : ImGuiColorEditFlags.HDR))
|| disabled)
return false;
if (_squaredRgb) if (_squaredRgb)
value = PseudoSquareRgb(value); value = PseudoSquareRgb(value);
if (_clamped) if (_clamped)
@ -175,11 +186,8 @@ public partial class ModEditWindow
value.CopyTo(values); value.CopyTo(values);
return true; return true;
} }
default: return FloatConstantEditor.Default.Draw(values, disabled, editorWidth);
return false;
} }
else
return FloatConstantEditor.Default.Draw(values, disabled, editorWidth);
} }
} }
@ -188,9 +196,7 @@ public partial class ModEditWindow
private readonly IReadOnlyList<(string Label, float Value, string Description)> _values; private readonly IReadOnlyList<(string Label, float Value, string Description)> _values;
public EnumConstantEditor(IReadOnlyList<(string Label, float Value, string Description)> values) public EnumConstantEditor(IReadOnlyList<(string Label, float Value, string Description)> values)
{ => _values = values;
_values = values;
}
public bool Draw(Span<float> values, bool disabled, float editorWidth) public bool Draw(Span<float> values, bool disabled, float editorWidth)
{ {
@ -200,34 +206,41 @@ public partial class ModEditWindow
for (var valueIdx = 0; valueIdx < values.Length; ++valueIdx) for (var valueIdx = 0; valueIdx < values.Length; ++valueIdx)
{ {
using var id = ImRaii.PushId(valueIdx);
if (valueIdx > 0) if (valueIdx > 0)
ImGui.SameLine(); ImGui.SameLine();
ImGui.SetNextItemWidth(MathF.Round(fieldWidth * (valueIdx + 1)) - MathF.Round(fieldWidth * valueIdx)); ImGui.SetNextItemWidth(MathF.Round(fieldWidth * (valueIdx + 1)) - MathF.Round(fieldWidth * valueIdx));
var currentValue = values[valueIdx]; var currentValue = values[valueIdx];
var (currentLabel, _, currentDescription) = _values.FirstOrNull(v => v.Value == currentValue) ?? (currentValue.ToString(), currentValue, string.Empty); var currentLabel = _values.FirstOrNull(v => v.Value == currentValue)?.Label
if (disabled) ?? currentValue.ToString(CultureInfo.CurrentCulture);
ImGui.InputText($"##{valueIdx}", ref currentLabel, (uint)currentLabel.Length, ImGuiInputTextFlags.ReadOnly); ret = disabled
else ? ImGui.InputText(string.Empty, ref currentLabel, (uint)currentLabel.Length, ImGuiInputTextFlags.ReadOnly)
: DrawCombo(currentLabel, ref values[valueIdx]);
}
return ret;
}
private bool DrawCombo(string label, ref float currentValue)
{ {
using var c = ImRaii.Combo($"##{valueIdx}", currentLabel); using var c = ImRaii.Combo(string.Empty, label);
{ if (!c)
if (c) return false;
var ret = false;
foreach (var (valueLabel, value, valueDescription) in _values) foreach (var (valueLabel, value, valueDescription) in _values)
{ {
if (ImGui.Selectable(valueLabel, value == currentValue)) if (ImGui.Selectable(valueLabel, value == currentValue))
{ {
values[valueIdx] = value; currentValue = value;
ret = true; ret = true;
} }
if (valueDescription.Length > 0) if (valueDescription.Length > 0)
ImGuiUtil.SelectableHelpMarker(valueDescription); ImGuiUtil.SelectableHelpMarker(valueDescription);
} }
}
}
}
return ret; return ret;
} }

View file

@ -6,7 +6,6 @@ using System.Linq;
using System.Numerics; using System.Numerics;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Interface.Internal.Notifications; using Dalamud.Interface.Internal.Notifications;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using ImGuiNET; using ImGuiNET;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@ -17,10 +16,8 @@ using Penumbra.GameData;
using Penumbra.GameData.Data; using Penumbra.GameData.Data;
using Penumbra.GameData.Files; using Penumbra.GameData.Files;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
using Penumbra.Services;
using Penumbra.String; using Penumbra.String;
using Penumbra.String.Classes; using Penumbra.String.Classes;
using Penumbra.Util;
using static Penumbra.GameData.Files.ShpkFile; using static Penumbra.GameData.Files.ShpkFile;
namespace Penumbra.UI.AdvancedWindow; namespace Penumbra.UI.AdvancedWindow;
@ -48,15 +45,17 @@ public partial class ModEditWindow
public ShpkFile? AssociatedShpk; public ShpkFile? AssociatedShpk;
public JObject? AssociatedShpkDevkit; public JObject? AssociatedShpkDevkit;
public readonly string LoadedBaseDevkitPathName = string.Empty; public readonly string LoadedBaseDevkitPathName;
public readonly JObject? AssociatedBaseDevkit; public readonly JObject? AssociatedBaseDevkit;
// Shader Key State // Shader Key State
public readonly List< (string Label, int Index, string Description, bool MonoFont, IReadOnlyList< (string Label, uint Value, string Description) > Values) > ShaderKeys = new(16); public readonly
List<(string Label, int Index, string Description, bool MonoFont, IReadOnlyList<(string Label, uint Value, string Description)>
Values)> ShaderKeys = new(16);
public readonly HashSet<int> VertexShaders = new(16); public readonly HashSet<int> VertexShaders = new(16);
public readonly HashSet<int> PixelShaders = new(16); public readonly HashSet<int> PixelShaders = new(16);
public bool ShadersKnown = false; public bool ShadersKnown;
public string VertexShadersString = "Vertex Shaders: ???"; public string VertexShadersString = "Vertex Shaders: ???";
public string PixelShadersString = "Pixel Shaders: ???"; public string PixelShadersString = "Pixel Shaders: ???";
@ -69,7 +68,9 @@ public partial class ModEditWindow
public bool UseColorDyeSet; public bool UseColorDyeSet;
// Material Constants // Material Constants
public readonly List< (string Header, List< (string Label, int ConstantIndex, Range Slice, string Description, bool MonoFont, IConstantEditor Editor) > Constants) > Constants = new(16); public readonly
List<(string Header, List<(string Label, int ConstantIndex, Range Slice, string Description, bool MonoFont, IConstantEditor Editor)>
Constants)> Constants = new(16);
// Live-Previewers // Live-Previewers
public readonly List<LiveMaterialPreviewer> MaterialPreviewers = new(4); public readonly List<LiveMaterialPreviewer> MaterialPreviewers = new(4);
@ -81,9 +82,7 @@ public partial class ModEditWindow
{ {
defaultPath = GamePaths.Shader.ShpkPath(Mtrl.ShaderPackage.Name); defaultPath = GamePaths.Shader.ShpkPath(Mtrl.ShaderPackage.Name);
if (!Utf8GamePath.FromString(defaultPath, out defaultGamePath, true)) if (!Utf8GamePath.FromString(defaultPath, out defaultGamePath, true))
{
return FullPath.Empty; return FullPath.Empty;
}
return _edit.FindBestMatch(defaultGamePath); return _edit.FindBestMatch(defaultGamePath);
} }
@ -120,7 +119,8 @@ public partial class ModEditWindow
LoadedShpkPath = FullPath.Empty; LoadedShpkPath = FullPath.Empty;
LoadedShpkPathName = string.Empty; LoadedShpkPathName = string.Empty;
AssociatedShpk = null; AssociatedShpk = null;
Penumbra.Chat.NotificationMessage( $"Could not load {LoadedShpkPath.ToPath()}:\n{e}", "Penumbra Advanced Editing", NotificationType.Error ); Penumbra.Chat.NotificationMessage($"Could not load {LoadedShpkPath.ToPath()}:\n{e}", "Penumbra Advanced Editing",
NotificationType.Error);
} }
if (LoadedShpkPath.InternalName.IsEmpty) if (LoadedShpkPath.InternalName.IsEmpty)
@ -129,7 +129,10 @@ public partial class ModEditWindow
LoadedShpkDevkitPathName = string.Empty; LoadedShpkDevkitPathName = string.Empty;
} }
else else
AssociatedShpkDevkit = TryLoadShpkDevkit( Path.GetFileNameWithoutExtension( Mtrl.ShaderPackage.Name ), out LoadedShpkDevkitPathName ); {
AssociatedShpkDevkit =
TryLoadShpkDevkit(Path.GetFileNameWithoutExtension(Mtrl.ShaderPackage.Name), out LoadedShpkDevkitPathName);
}
UpdateShaderKeys(); UpdateShaderKeys();
Update(); Update();
@ -157,10 +160,8 @@ public partial class ModEditWindow
} }
private T? TryGetShpkDevkitData<T>(string category, uint? id, bool mayVary) where T : class private T? TryGetShpkDevkitData<T>(string category, uint? id, bool mayVary) where T : class
{ => TryGetShpkDevkitData<T>(AssociatedShpkDevkit, LoadedShpkDevkitPathName, category, id, mayVary)
return TryGetShpkDevkitData<T>(AssociatedShpkDevkit, LoadedShpkDevkitPathName, category, id, mayVary)
?? TryGetShpkDevkitData<T>(AssociatedBaseDevkit, LoadedBaseDevkitPathName, category, id, mayVary); ?? TryGetShpkDevkitData<T>(AssociatedBaseDevkit, LoadedBaseDevkitPathName, category, id, mayVary);
}
private T? TryGetShpkDevkitData<T>(JObject? devkit, string devkitPathName, string category, uint? id, bool mayVary) where T : class private T? TryGetShpkDevkitData<T>(JObject? devkit, string devkitPathName, string category, uint? id, bool mayVary) where T : class
{ {
@ -175,7 +176,7 @@ public partial class ModEditWindow
if (mayVary && (data as JObject)?["Vary"] != null) if (mayVary && (data as JObject)?["Vary"] != null)
{ {
var selector = BuildSelector(data!["Vary"]! var selector = BuildSelector(data["Vary"]!
.Select(key => (uint)key) .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()]!; var index = (int)data["Selectors"]![selector.ToString()]!;
@ -192,11 +193,10 @@ public partial class ModEditWindow
} }
} }
public void UpdateShaderKeys() private void UpdateShaderKeys()
{ {
ShaderKeys.Clear(); ShaderKeys.Clear();
if (AssociatedShpk != null) if (AssociatedShpk != null)
{
foreach (var key in AssociatedShpk.MaterialKeys) foreach (var key in AssociatedShpk.MaterialKeys)
{ {
var dkData = TryGetShpkDevkitData<DevkitShaderKey>("ShaderKeys", key.Id, false); var dkData = TryGetShpkDevkitData<DevkitShaderKey>("ShaderKeys", key.Id, false);
@ -211,7 +211,7 @@ public partial class ModEditWindow
{ {
if (dkData != null && dkData.Values.TryGetValue(value, out var dkValue)) if (dkData != null && dkData.Values.TryGetValue(value, out var dkValue))
return (dkValue.Label.Length > 0 ? dkValue.Label : $"0x{value:X8}", value, dkValue.Description); return (dkValue.Label.Length > 0 ? dkValue.Label : $"0x{value:X8}", value, dkValue.Description);
else
return ($"0x{value:X8}", value, string.Empty); return ($"0x{value:X8}", value, string.Empty);
}).ToArray(); }).ToArray();
Array.Sort(values, (x, y) => Array.Sort(values, (x, y) =>
@ -220,31 +220,33 @@ public partial class ModEditWindow
return -1; return -1;
if (y.Value == key.DefaultValue) if (y.Value == key.DefaultValue)
return 1; return 1;
return x.Label.CompareTo(y.Label);
return string.Compare(x.Label, y.Label, StringComparison.Ordinal);
}); });
ShaderKeys.Add((hasDkLabel ? dkData!.Label : $"0x{key.Id:X8}", mtrlKeyIndex, dkData?.Description ?? string.Empty, !hasDkLabel, values)); ShaderKeys.Add((hasDkLabel ? dkData!.Label : $"0x{key.Id:X8}", mtrlKeyIndex, dkData?.Description ?? string.Empty,
} !hasDkLabel, values));
} }
else else
{
foreach (var (key, index) in Mtrl.ShaderPackage.ShaderKeys.WithIndex()) foreach (var (key, index) in Mtrl.ShaderPackage.ShaderKeys.WithIndex())
ShaderKeys.Add(($"0x{key.Category:X8}", index, string.Empty, true, Array.Empty<(string, uint, string)>())); ShaderKeys.Add(($"0x{key.Category:X8}", index, string.Empty, true, Array.Empty<(string, uint, string)>()));
} }
}
public void UpdateShaders() private void UpdateShaders()
{ {
VertexShaders.Clear(); VertexShaders.Clear();
PixelShaders.Clear(); PixelShaders.Clear();
if (AssociatedShpk == null) if (AssociatedShpk == null)
{
ShadersKnown = false; ShadersKnown = false;
}
else else
{ {
ShadersKnown = true; ShadersKnown = true;
var systemKeySelectors = AllSelectors(AssociatedShpk.SystemKeys).ToArray(); var systemKeySelectors = AllSelectors(AssociatedShpk.SystemKeys).ToArray();
var sceneKeySelectors = AllSelectors(AssociatedShpk.SceneKeys).ToArray(); var sceneKeySelectors = AllSelectors(AssociatedShpk.SceneKeys).ToArray();
var subViewKeySelectors = AllSelectors(AssociatedShpk.SubViewKeys).ToArray(); var subViewKeySelectors = AllSelectors(AssociatedShpk.SubViewKeys).ToArray();
var materialKeySelector = BuildSelector(AssociatedShpk.MaterialKeys.Select(key => Mtrl.GetOrAddShaderKey(key.Id, key.DefaultValue).Value)); var materialKeySelector =
BuildSelector(AssociatedShpk.MaterialKeys.Select(key => Mtrl.GetOrAddShaderKey(key.Id, key.DefaultValue).Value));
foreach (var systemKeySelector in systemKeySelectors) foreach (var systemKeySelector in systemKeySelectors)
{ {
foreach (var sceneKeySelector in sceneKeySelectors) foreach (var sceneKeySelector in sceneKeySelectors)
@ -254,13 +256,11 @@ public partial class ModEditWindow
var selector = BuildSelector(systemKeySelector, sceneKeySelector, materialKeySelector, subViewKeySelector); var selector = BuildSelector(systemKeySelector, sceneKeySelector, materialKeySelector, subViewKeySelector);
var node = AssociatedShpk.GetNodeBySelector(selector); var node = AssociatedShpk.GetNodeBySelector(selector);
if (node.HasValue) if (node.HasValue)
{
foreach (var pass in node.Value.Passes) foreach (var pass in node.Value.Passes)
{ {
VertexShaders.Add((int)pass.VertexShader); VertexShaders.Add((int)pass.VertexShader);
PixelShaders.Add((int)pass.PixelShader); PixelShaders.Add((int)pass.PixelShader);
} }
}
else else
ShadersKnown = false; ShadersKnown = false;
} }
@ -277,7 +277,7 @@ public partial class ModEditWindow
ShaderComment = TryGetShpkDevkitData<string>("Comment", null, true) ?? string.Empty; ShaderComment = TryGetShpkDevkitData<string>("Comment", null, true) ?? string.Empty;
} }
public void UpdateTextures() private void UpdateTextures()
{ {
Textures.Clear(); Textures.Clear();
SamplerIds.Clear(); SamplerIds.Clear();
@ -302,50 +302,63 @@ public partial class ModEditWindow
if (Mtrl.ColorSets.Any(c => c.HasRows)) if (Mtrl.ColorSets.Any(c => c.HasRows))
SamplerIds.Add(TableSamplerId); SamplerIds.Add(TableSamplerId);
} }
foreach (var samplerId in SamplerIds) foreach (var samplerId in SamplerIds)
{ {
var shpkSampler = AssociatedShpk.GetSamplerById(samplerId); var shpkSampler = AssociatedShpk.GetSamplerById(samplerId);
if (!shpkSampler.HasValue || shpkSampler.Value.Slot != 2) if (shpkSampler is not { Slot: 2 })
continue; continue;
var dkData = TryGetShpkDevkitData<DevkitSampler>("Samplers", samplerId, true); var dkData = TryGetShpkDevkitData<DevkitSampler>("Samplers", samplerId, true);
var hasDkLabel = !string.IsNullOrEmpty(dkData?.Label); var hasDkLabel = !string.IsNullOrEmpty(dkData?.Label);
var sampler = Mtrl.GetOrAddSampler(samplerId, dkData?.DefaultTexture ?? string.Empty, out var samplerIndex); var sampler = Mtrl.GetOrAddSampler(samplerId, dkData?.DefaultTexture ?? string.Empty, out var samplerIndex);
Textures.Add((hasDkLabel ? dkData!.Label : shpkSampler.Value.Name, sampler.TextureIndex, samplerIndex, dkData?.Description ?? string.Empty, !hasDkLabel)); Textures.Add((hasDkLabel ? dkData!.Label : shpkSampler.Value.Name, sampler.TextureIndex, samplerIndex,
dkData?.Description ?? string.Empty, !hasDkLabel));
} }
if (SamplerIds.Contains(TableSamplerId)) if (SamplerIds.Contains(TableSamplerId))
Mtrl.FindOrAddColorSet(); Mtrl.FindOrAddColorSet();
} }
Textures.Sort((x, y) => string.CompareOrdinal(x.Label, y.Label)); Textures.Sort((x, y) => string.CompareOrdinal(x.Label, y.Label));
TextureLabelWidth = 50f * UiHelpers.Scale; TextureLabelWidth = 50f * UiHelpers.Scale;
float helpWidth; float helpWidth;
using (var _ = ImRaii.PushFont(UiBuilder.IconFont)) using (var _ = ImRaii.PushFont(UiBuilder.IconFont))
{
helpWidth = ImGui.GetStyle().ItemSpacing.X + ImGui.CalcTextSize(FontAwesomeIcon.InfoCircle.ToIconString()).X; helpWidth = ImGui.GetStyle().ItemSpacing.X + ImGui.CalcTextSize(FontAwesomeIcon.InfoCircle.ToIconString()).X;
}
foreach (var (label, _, _, description, monoFont) in Textures) foreach (var (label, _, _, description, monoFont) in Textures)
{
if (!monoFont) if (!monoFont)
TextureLabelWidth = Math.Max(TextureLabelWidth, ImGui.CalcTextSize(label).X + (description.Length > 0 ? helpWidth : 0.0f)); TextureLabelWidth = Math.Max(TextureLabelWidth, ImGui.CalcTextSize(label).X + (description.Length > 0 ? helpWidth : 0.0f));
}
using (var _ = ImRaii.PushFont(UiBuilder.MonoFont)) using (var _ = ImRaii.PushFont(UiBuilder.MonoFont))
{ {
foreach (var (label, _, _, description, monoFont) in Textures) foreach (var (label, _, _, description, monoFont) in Textures)
{
if (monoFont) if (monoFont)
TextureLabelWidth = Math.Max(TextureLabelWidth, ImGui.CalcTextSize(label).X + (description.Length > 0 ? helpWidth : 0.0f)); TextureLabelWidth = Math.Max(TextureLabelWidth,
ImGui.CalcTextSize(label).X + (description.Length > 0 ? helpWidth : 0.0f));
}
} }
TextureLabelWidth = TextureLabelWidth / UiHelpers.Scale + 4; TextureLabelWidth = TextureLabelWidth / UiHelpers.Scale + 4;
} }
public void UpdateConstants() private void UpdateConstants()
{ {
static List<T> FindOrAddGroup<T>(List<(string, List<T>)> groups, string name) static List<T> FindOrAddGroup<T>(List<(string, List<T>)> groups, string name)
{ {
foreach (var (groupName, group) in groups) foreach (var (groupName, group) in groups)
{
if (string.Equals(name, groupName, StringComparison.Ordinal)) if (string.Equals(name, groupName, StringComparison.Ordinal))
return group; return group;
}
var newGroup = new List<T>(16); var newGroup = new List<T>(16);
groups.Add((name, newGroup)); groups.Add((name, newGroup));
@ -360,7 +373,10 @@ public partial class ModEditWindow
{ {
var values = Mtrl.GetConstantValues(constant); var values = Mtrl.GetConstantValues(constant);
for (var i = 0; i < values.Length; i += 4) for (var i = 0; i < values.Length; i += 4)
fcGroup.Add(($"0x{constant.Id:X8}", index, i..Math.Min(i + 4, values.Length), string.Empty, true, FloatConstantEditor.Default)); {
fcGroup.Add(($"0x{constant.Id:X8}", index, i..Math.Min(i + 4, values.Length), string.Empty, true,
FloatConstantEditor.Default));
}
} }
} }
else else
@ -377,7 +393,6 @@ public partial class ModEditWindow
var dkData = TryGetShpkDevkitData<DevkitConstant[]>("Constants", shpkConstant.Id, true); var dkData = TryGetShpkDevkitData<DevkitConstant[]>("Constants", shpkConstant.Id, true);
if (dkData != null) if (dkData != null)
{
foreach (var dkConstant in dkData) foreach (var dkConstant in dkData)
{ {
var offset = (int)dkConstant.Offset; var offset = (int)dkConstant.Offset;
@ -386,13 +401,13 @@ public partial class ModEditWindow
length = Math.Min(length, (int)dkConstant.Length.Value); length = Math.Min(length, (int)dkConstant.Length.Value);
if (length <= 0) if (length <= 0)
continue; continue;
var editor = dkConstant.CreateEditor(); var editor = dkConstant.CreateEditor();
if (editor != null) if (editor != null)
FindOrAddGroup(Constants, dkConstant.Group.Length > 0 ? dkConstant.Group : "Further Constants") FindOrAddGroup(Constants, dkConstant.Group.Length > 0 ? dkConstant.Group : "Further Constants")
.Add((dkConstant.Label, constantIndex, offset..(offset + length), dkConstant.Description, false, editor)); .Add((dkConstant.Label, constantIndex, offset..(offset + length), dkConstant.Description, false, editor));
handledElements.AddRange(offset, length); handledElements.AddRange(offset, length);
} }
}
var fcGroup = FindOrAddGroup(Constants, "Further Constants"); var fcGroup = FindOrAddGroup(Constants, "Further Constants");
foreach (var (start, end) in handledElements.Ranges(true)) foreach (var (start, end) in handledElements.Ranges(true))
@ -405,13 +420,18 @@ public partial class ModEditWindow
var rangeStart = Math.Max(i, start); var rangeStart = Math.Max(i, start);
var rangeEnd = Math.Min(i + 4, end); var rangeEnd = Math.Min(i + 4, end);
if (rangeEnd > rangeStart) if (rangeEnd > rangeStart)
fcGroup.Add(($"{prefix}[{j:D2}]{VectorSwizzle((offset + rangeStart) & 0x3, (offset + rangeEnd - 1) & 0x3)} (0x{shpkConstant.Id:X8})", constantIndex, rangeStart..rangeEnd, string.Empty, true, FloatConstantEditor.Default)); fcGroup.Add((
$"{prefix}[{j:D2}]{VectorSwizzle((offset + rangeStart) & 0x3, (offset + rangeEnd - 1) & 0x3)} (0x{shpkConstant.Id:X8})",
constantIndex, rangeStart..rangeEnd, string.Empty, true, FloatConstantEditor.Default));
} }
} }
else else
{ {
for (var i = start; i < end; i += 4) for (var i = start; i < end; i += 4)
fcGroup.Add(($"0x{shpkConstant.Id:X8}", constantIndex, i..Math.Min(i + 4, end), string.Empty, true, FloatConstantEditor.Default)); {
fcGroup.Add(($"0x{shpkConstant.Id:X8}", constantIndex, i..Math.Min(i + 4, end), string.Empty, true,
FloatConstantEditor.Default));
}
} }
} }
} }
@ -424,20 +444,23 @@ public partial class ModEditWindow
return 1; return 1;
if (string.Equals(y.Header, "Further Constants", StringComparison.Ordinal)) if (string.Equals(y.Header, "Further Constants", StringComparison.Ordinal))
return -1; return -1;
return string.Compare(x.Header, y.Header, StringComparison.Ordinal); return string.Compare(x.Header, y.Header, StringComparison.Ordinal);
}); });
// HACK the Replace makes w appear after xyz, for the cbuffer-location-based naming scheme // HACK the Replace makes w appear after xyz, for the cbuffer-location-based naming scheme
foreach (var (_, group) in Constants) foreach (var (_, group) in Constants)
{
group.Sort((x, y) => string.CompareOrdinal( group.Sort((x, y) => string.CompareOrdinal(
x.MonoFont ? x.Label.Replace("].w", "].{") : x.Label, x.MonoFont ? x.Label.Replace("].w", "].{") : x.Label,
y.MonoFont ? y.Label.Replace("].w", "].{") : y.Label)); y.MonoFont ? y.Label.Replace("].w", "].{") : y.Label));
} }
}
public unsafe void BindToMaterialInstances() public unsafe void BindToMaterialInstances()
{ {
UnbindFromMaterialInstances(); UnbindFromMaterialInstances();
var localPlayer = FindLocalPlayer(_edit._dalamud.Objects); var localPlayer = LocalPlayer(_edit._dalamud.Objects);
if (null == localPlayer) if (null == localPlayer)
return; return;
@ -449,7 +472,9 @@ public partial class ModEditWindow
var drawObjects = stackalloc CharacterBase*[4]; var drawObjects = stackalloc CharacterBase*[4];
drawObjects[0] = drawObject; drawObjects[0] = drawObject;
drawObjects[1] = *((CharacterBase**)&localPlayer->DrawData.MainHand + 1);
drawObjects[2] = *((CharacterBase**)&localPlayer->DrawData.OffHand + 1);
drawObjects[3] = *((CharacterBase**)&localPlayer->DrawData.UnkF0 + 1);
for (var i = 0; i < 3; ++i) for (var i = 0; i < 3; ++i)
{ {
var subActor = FindSubActor(localPlayer, i); var subActor = FindSubActor(localPlayer, i);
@ -470,9 +495,11 @@ public partial class ModEditWindow
var material = GetDrawObjectMaterial(drawObjects[subActorType + 1], modelSlot, materialSlot); var material = GetDrawObjectMaterial(drawObjects[subActorType + 1], modelSlot, materialSlot);
if (foundMaterials.Contains((nint)material)) if (foundMaterials.Contains((nint)material))
continue; continue;
try try
{ {
MaterialPreviewers.Add(new LiveMaterialPreviewer(_edit._dalamud.Objects, subActorType, childObjectIndex, modelSlot, materialSlot)); MaterialPreviewers.Add(new LiveMaterialPreviewer(_edit._dalamud.Objects, subActorType, childObjectIndex, modelSlot,
materialSlot));
foundMaterials.Add((nint)material); foundMaterials.Add((nint)material);
} }
catch (InvalidOperationException) catch (InvalidOperationException)
@ -480,28 +507,31 @@ public partial class ModEditWindow
// Carry on without that previewer. // Carry on without that previewer.
} }
} }
UpdateMaterialPreview(); UpdateMaterialPreview();
var colorSet = Mtrl.ColorSets.FirstOrNull(colorSet => colorSet.HasRows); var colorSet = Mtrl.ColorSets.FirstOrNull(colorSet => colorSet.HasRows);
if (colorSet.HasValue) if (!colorSet.HasValue)
{ return;
foreach (var (subActorType, childObjectIndex, modelSlot, materialSlot) in instances) foreach (var (subActorType, childObjectIndex, modelSlot, materialSlot) in instances)
{ {
try try
{ {
ColorSetPreviewers.Add(new LiveColorSetPreviewer(_edit._dalamud.Objects, _edit._dalamud.Framework, subActorType, childObjectIndex, modelSlot, materialSlot)); ColorSetPreviewers.Add(new LiveColorSetPreviewer(_edit._dalamud.Objects, _edit._dalamud.Framework, subActorType,
childObjectIndex, modelSlot, materialSlot));
} }
catch (InvalidOperationException) catch (InvalidOperationException)
{ {
// Carry on without that previewer. // Carry on without that previewer.
} }
} }
UpdateColorSetPreview(); UpdateColorSetPreview();
} }
}
public void UnbindFromMaterialInstances() private void UnbindFromMaterialInstances()
{ {
foreach (var previewer in MaterialPreviewers) foreach (var previewer in MaterialPreviewers)
previewer.Dispose(); previewer.Dispose();
@ -512,7 +542,7 @@ public partial class ModEditWindow
ColorSetPreviewers.Clear(); ColorSetPreviewers.Clear();
} }
public unsafe void UnbindFromDrawObjectMaterialInstances(nint characterBase) private unsafe void UnbindFromDrawObjectMaterialInstances(nint characterBase)
{ {
for (var i = MaterialPreviewers.Count; i-- > 0;) for (var i = MaterialPreviewers.Count; i-- > 0;)
{ {
@ -553,7 +583,7 @@ public partial class ModEditWindow
previewer.SetSamplerFlags(samplerCrc, samplerFlags); previewer.SetSamplerFlags(samplerCrc, samplerFlags);
} }
public void UpdateMaterialPreview() private void UpdateMaterialPreview()
{ {
SetShaderPackageFlags(Mtrl.ShaderPackage.Flags); SetShaderPackageFlags(Mtrl.ShaderPackage.Flags);
foreach (var constant in Mtrl.ShaderPackage.Constants) foreach (var constant in Mtrl.ShaderPackage.Constants)
@ -562,6 +592,7 @@ public partial class ModEditWindow
if (values != null) if (values != null)
SetMaterialParameter(constant.Id, 0, values); SetMaterialParameter(constant.Id, 0, values);
} }
foreach (var sampler in Mtrl.ShaderPackage.Samplers) foreach (var sampler in Mtrl.ShaderPackage.Samplers)
SetSamplerFlags(sampler.SamplerId, sampler.Flags); SetSamplerFlags(sampler.SamplerId, sampler.Flags);
} }
@ -610,7 +641,7 @@ public partial class ModEditWindow
{ {
var stm = _edit._stainService.StmFile; var stm = _edit._stainService.StmFile;
var dye = maybeColorDyeSet.Value.Rows[rowIdx]; var dye = maybeColorDyeSet.Value.Rows[rowIdx];
if (stm.TryGetValue(dye.Template, (StainId)_edit._stainService.StainCombo.CurrentSelection.Key, out var dyes)) if (stm.TryGetValue(dye.Template, _edit._stainService.StainCombo.CurrentSelection.Key, out var dyes))
row.ApplyDyeTemplate(dye, dyes); row.ApplyDyeTemplate(dye, dyes);
} }
@ -619,7 +650,8 @@ public partial class ModEditWindow
foreach (var previewer in ColorSetPreviewers) foreach (var previewer in ColorSetPreviewers)
{ {
row.AsHalves().CopyTo(previewer.ColorSet.AsSpan().Slice(LiveColorSetPreviewer.TextureWidth * 4 * rowIdx, LiveColorSetPreviewer.TextureWidth * 4)); row.AsHalves().CopyTo(previewer.ColorSet.AsSpan()
.Slice(LiveColorSetPreviewer.TextureWidth * 4 * rowIdx, LiveColorSetPreviewer.TextureWidth * 4));
previewer.ScheduleUpdate(); previewer.ScheduleUpdate();
} }
} }
@ -694,18 +726,7 @@ public partial class ModEditWindow
} }
} }
~MtrlTab()
{
DoDispose();
}
public void Dispose() public void Dispose()
{
DoDispose();
GC.SuppressFinalize(this);
}
private void DoDispose()
{ {
UnbindFromMaterialInstances(); UnbindFromMaterialInstances();
if (Writable) if (Writable)
@ -723,11 +744,7 @@ public partial class ModEditWindow
return output.Write(); return output.Write();
} }
private sealed class DevkitShaderKeyValue private sealed record DevkitShaderKeyValue(string Label = "", string Description = "");
{
public string Label = string.Empty;
public string Description = string.Empty;
}
private sealed class DevkitShaderKey private sealed class DevkitShaderKey
{ {
@ -736,12 +753,7 @@ public partial class ModEditWindow
public Dictionary<uint, DevkitShaderKeyValue> Values = new(); public Dictionary<uint, DevkitShaderKeyValue> Values = new();
} }
private sealed class DevkitSampler private sealed record DevkitSampler(string Label = "", string Description = "", string DefaultTexture = "");
{
public string Label = string.Empty;
public string Description = string.Empty;
public string DefaultTexture = string.Empty;
}
private enum DevkitConstantType private enum DevkitConstantType
{ {
@ -752,12 +764,7 @@ public partial class ModEditWindow
Enum = 3, Enum = 3,
} }
private sealed class DevkitConstantValue private sealed record DevkitConstantValue(string Label = "", string Description = "", float Value = 0);
{
public string Label = string.Empty;
public string Description = string.Empty;
public float Value = 0.0f;
}
private sealed class DevkitConstant private sealed class DevkitConstant
{ {
@ -783,25 +790,20 @@ public partial class ModEditWindow
public DevkitConstantValue[] Values = Array.Empty<DevkitConstantValue>(); public DevkitConstantValue[] Values = Array.Empty<DevkitConstantValue>();
public IConstantEditor? CreateEditor() public IConstantEditor? CreateEditor()
=> Type switch
{ {
switch (Type) DevkitConstantType.Hidden => null,
{ DevkitConstantType.Float => new FloatConstantEditor(Minimum, Maximum, Speed ?? 0.1f, RelativeSpeed, Factor, Bias, Precision,
case DevkitConstantType.Hidden: Unit),
return null; DevkitConstantType.Integer => new IntConstantEditor(ToInteger(Minimum), ToInteger(Maximum), Speed ?? 0.25f, RelativeSpeed,
case DevkitConstantType.Float: Factor, Bias, Unit),
return new FloatConstantEditor(Minimum, Maximum, Speed ?? 0.1f, RelativeSpeed, Factor, Bias, Precision, Unit); DevkitConstantType.Color => new ColorConstantEditor(SquaredRgb, Clamped),
case DevkitConstantType.Integer: DevkitConstantType.Enum => new EnumConstantEditor(Array.ConvertAll(Values,
return new IntConstantEditor(ToInteger(Minimum), ToInteger(Maximum), Speed ?? 0.25f, RelativeSpeed, Factor, Bias, Unit); value => (value.Label, value.Value, value.Description))),
case DevkitConstantType.Color: _ => FloatConstantEditor.Default,
return new ColorConstantEditor(SquaredRgb, Clamped); };
case DevkitConstantType.Enum:
return new EnumConstantEditor(Array.ConvertAll(Values, value => (value.Label, value.Value, value.Description)));
default:
return FloatConstantEditor.Default;
}
}
private int? ToInteger(float? value) private static int? ToInteger(float? value)
=> value.HasValue ? (int)Math.Clamp(MathF.Round(value.Value), int.MinValue, int.MaxValue) : null; => value.HasValue ? (int)Math.Clamp(MathF.Round(value.Value), int.MinValue, int.MaxValue) : null;
} }
} }

View file

@ -1,18 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics; using System.Numerics;
using System.Text; using System.Text;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Interface.ImGuiFileDialog;
using ImGuiNET; using ImGuiNET;
using Lumina.Data.Parsing;
using Lumina.Excel.GeneratedSheets;
using OtterGui; using OtterGui;
using OtterGui.Raii; using OtterGui.Raii;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.GameData.Files;
using Penumbra.String.Classes; using Penumbra.String.Classes;
namespace Penumbra.UI.AdvancedWindow; namespace Penumbra.UI.AdvancedWindow;
@ -25,7 +19,7 @@ public partial class ModEditWindow
// Apricot shader packages are unlisted because // Apricot shader packages are unlisted because
// 1. they cause performance/memory issues when calculating the effective shader set // 1. they cause performance/memory issues when calculating the effective shader set
// 2. they probably aren't intended for use with materials anyway // 2. they probably aren't intended for use with materials anyway
private static readonly IReadOnlyList<string> StandardShaderPackages = new string[] private static readonly IReadOnlyList<string> StandardShaderPackages = new[]
{ {
"3dui.shpk", "3dui.shpk",
// "apricot_decal_dummy.shpk", // "apricot_decal_dummy.shpk",
@ -76,7 +70,7 @@ public partial class ModEditWindow
Border = 3, Border = 3,
} }
private static readonly IReadOnlyList<string> TextureAddressModeTooltips = new string[] private static readonly IReadOnlyList<string> TextureAddressModeTooltips = new[]
{ {
"Tile the texture at every UV integer junction.\n\nFor example, for U values between 0 and 3, the texture is repeated three times.", "Tile the texture at every UV integer junction.\n\nFor example, for U values between 0 and 3, the texture is repeated three times.",
"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.", "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.",
@ -113,18 +107,15 @@ public partial class ModEditWindow
private static bool DrawShaderFlagsInput(MtrlTab tab, bool disabled) private static bool DrawShaderFlagsInput(MtrlTab tab, bool disabled)
{ {
var ret = false;
var shpkFlags = (int)tab.Mtrl.ShaderPackage.Flags; var shpkFlags = (int)tab.Mtrl.ShaderPackage.Flags;
ImGui.SetNextItemWidth(UiHelpers.Scale * 250.0f); ImGui.SetNextItemWidth(UiHelpers.Scale * 250.0f);
if (ImGui.InputInt("Shader Flags", ref shpkFlags, 0, 0, if (!ImGui.InputInt("Shader Flags", ref shpkFlags, 0, 0,
ImGuiInputTextFlags.CharsHexadecimal | (disabled ? ImGuiInputTextFlags.ReadOnly : ImGuiInputTextFlags.None))) ImGuiInputTextFlags.CharsHexadecimal | (disabled ? ImGuiInputTextFlags.ReadOnly : ImGuiInputTextFlags.None)))
{ return false;
tab.Mtrl.ShaderPackage.Flags = (uint)shpkFlags;
ret = true;
tab.SetShaderPackageFlags((uint)shpkFlags);
}
return ret; tab.Mtrl.ShaderPackage.Flags = (uint)shpkFlags;
tab.SetShaderPackageFlags((uint)shpkFlags);
return true;
} }
/// <summary> /// <summary>

View file

@ -6,6 +6,7 @@ using OtterGui;
using OtterGui.Raii; using OtterGui.Raii;
using Penumbra.GameData.Files; using Penumbra.GameData.Files;
using Penumbra.String.Classes; using Penumbra.String.Classes;
using Penumbra.UI.Classes;
namespace Penumbra.UI.AdvancedWindow; namespace Penumbra.UI.AdvancedWindow;
@ -41,31 +42,23 @@ public partial class ModEditWindow
if (ImGui.Button("Reload live preview")) if (ImGui.Button("Reload live preview"))
tab.BindToMaterialInstances(); tab.BindToMaterialInstances();
if (tab.MaterialPreviewers.Count == 0 && tab.ColorSetPreviewers.Count == 0) if (tab.MaterialPreviewers.Count != 0 || tab.ColorSetPreviewers.Count != 0)
{ return;
ImGui.SameLine(); ImGui.SameLine();
using var c = ImRaii.PushColor(ImGuiCol.Text, Colors.RegexWarningBorder);
var textColor = ImGui.GetColorU32(ImGuiCol.Text); ImGui.TextUnformatted(
var textColorWarning = (textColor & 0xFF000000u) | ((textColor & 0x00FEFEFE) >> 1) | 0x80u; // Half red "The current material has not been found on your character. Please check the Import from Screen tab for more information.");
using var c = ImRaii.PushColor(ImGuiCol.Text, textColorWarning);
ImGui.TextUnformatted("The current material has not been found on your character. Please check the Import from Screen tab for more information.");
}
} }
private static bool DrawMaterialTextureChange(MtrlTab tab, bool disabled) private static bool DrawMaterialTextureChange(MtrlTab tab, bool disabled)
{ {
if (tab.Textures.Count == 0) if (tab.Textures.Count == 0)
{
return false; return false;
}
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2)); ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
if (!ImGui.CollapsingHeader("Textures and Samplers", ImGuiTreeNodeFlags.DefaultOpen)) if (!ImGui.CollapsingHeader("Textures and Samplers", ImGuiTreeNodeFlags.DefaultOpen))
{
return false; return false;
}
var frameHeight = ImGui.GetFrameHeight(); var frameHeight = ImGui.GetFrameHeight();
var ret = false; var ret = false;
@ -74,15 +67,14 @@ public partial class ModEditWindow
ImGui.TableSetupColumn(string.Empty, ImGuiTableColumnFlags.WidthFixed, frameHeight); ImGui.TableSetupColumn(string.Empty, ImGuiTableColumnFlags.WidthFixed, frameHeight);
ImGui.TableSetupColumn("Path", ImGuiTableColumnFlags.WidthStretch); ImGui.TableSetupColumn("Path", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.WidthFixed, tab.TextureLabelWidth * UiHelpers.Scale); ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.WidthFixed, tab.TextureLabelWidth * UiHelpers.Scale);
for( var i = 0; i < tab.Textures.Count; ++i ) foreach (var (label, textureI, samplerI, description, monoFont) in tab.Textures)
{ {
var (label, textureI, samplerI, description, monoFont) = tab.Textures[i];
using var _ = ImRaii.PushId(samplerI); using var _ = ImRaii.PushId(samplerI);
var tmp = tab.Mtrl.Textures[textureI].Path; var tmp = tab.Mtrl.Textures[textureI].Path;
var unfolded = tab.UnfoldedTextures.Contains(samplerI); var unfolded = tab.UnfoldedTextures.Contains(samplerI);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
if( ImGuiUtil.DrawDisabledButton( ( unfolded ? FontAwesomeIcon.CaretDown : FontAwesomeIcon.CaretRight ).ToIconString(), new Vector2( frameHeight ), if (ImGuiUtil.DrawDisabledButton((unfolded ? FontAwesomeIcon.CaretDown : FontAwesomeIcon.CaretRight).ToIconString(),
new Vector2(frameHeight),
"Settings for this texture and the associated sampler", false, true)) "Settings for this texture and the associated sampler", false, true))
{ {
unfolded = !unfolded; unfolded = !unfolded;
@ -91,6 +83,7 @@ public partial class ModEditWindow
else else
tab.UnfoldedTextures.Remove(samplerI); tab.UnfoldedTextures.Remove(samplerI);
} }
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X); ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X);
if (ImGui.InputText(string.Empty, ref tmp, Utf8GamePath.MaxGamePathLength, if (ImGui.InputText(string.Empty, ref tmp, Utf8GamePath.MaxGamePathLength,
@ -136,7 +129,8 @@ public partial class ModEditWindow
var tmp = (tab.Mtrl.ShaderPackage.Flags & transparencyBit) != 0; var tmp = (tab.Mtrl.ShaderPackage.Flags & transparencyBit) != 0;
if (ImGui.Checkbox("Enable Transparency", ref tmp)) if (ImGui.Checkbox("Enable Transparency", ref tmp))
{ {
tab.Mtrl.ShaderPackage.Flags = tmp ? tab.Mtrl.ShaderPackage.Flags | transparencyBit : tab.Mtrl.ShaderPackage.Flags & ~transparencyBit; tab.Mtrl.ShaderPackage.Flags =
tmp ? tab.Mtrl.ShaderPackage.Flags | transparencyBit : tab.Mtrl.ShaderPackage.Flags & ~transparencyBit;
ret = true; ret = true;
tab.SetShaderPackageFlags(tab.Mtrl.ShaderPackage.Flags); tab.SetShaderPackageFlags(tab.Mtrl.ShaderPackage.Flags);
} }
@ -156,45 +150,31 @@ public partial class ModEditWindow
private static void DrawOtherMaterialDetails(MtrlFile file, bool _) private static void DrawOtherMaterialDetails(MtrlFile file, bool _)
{ {
if (!ImGui.CollapsingHeader("Further Content")) if (!ImGui.CollapsingHeader("Further Content"))
{
return; return;
}
using (var sets = ImRaii.TreeNode("UV Sets", ImGuiTreeNodeFlags.DefaultOpen)) using (var sets = ImRaii.TreeNode("UV Sets", ImGuiTreeNodeFlags.DefaultOpen))
{ {
if (sets) if (sets)
{
foreach (var set in file.UvSets) foreach (var set in file.UvSets)
{
ImRaii.TreeNode($"#{set.Index:D2} - {set.Name}", ImGuiTreeNodeFlags.Leaf).Dispose(); ImRaii.TreeNode($"#{set.Index:D2} - {set.Name}", ImGuiTreeNodeFlags.Leaf).Dispose();
} }
}
}
if (file.AdditionalData.Length <= 0) if (file.AdditionalData.Length <= 0)
{
return; return;
}
using var t = ImRaii.TreeNode($"Additional Data (Size: {file.AdditionalData.Length})###AdditionalData"); using var t = ImRaii.TreeNode($"Additional Data (Size: {file.AdditionalData.Length})###AdditionalData");
if (t) if (t)
{
ImGuiUtil.TextWrapped(string.Join(' ', file.AdditionalData.Select(c => $"{c:X2}"))); ImGuiUtil.TextWrapped(string.Join(' ', file.AdditionalData.Select(c => $"{c:X2}")));
} }
}
private void DrawMaterialReassignmentTab() private void DrawMaterialReassignmentTab()
{ {
if (_editor.Files.Mdl.Count == 0) if (_editor.Files.Mdl.Count == 0)
{
return; return;
}
using var tab = ImRaii.TabItem("Material Reassignment"); using var tab = ImRaii.TabItem("Material Reassignment");
if (!tab) if (!tab)
{
return; return;
}
ImGui.NewLine(); ImGui.NewLine();
MaterialSuffix.Draw(_editor, ImGuiHelpers.ScaledVector2(175, 0)); MaterialSuffix.Draw(_editor, ImGuiHelpers.ScaledVector2(175, 0));
@ -202,15 +182,11 @@ public partial class ModEditWindow
ImGui.NewLine(); ImGui.NewLine();
using var child = ImRaii.Child("##mdlFiles", -Vector2.One, true); using var child = ImRaii.Child("##mdlFiles", -Vector2.One, true);
if (!child) if (!child)
{
return; return;
}
using var table = ImRaii.Table("##files", 4, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, -Vector2.One); using var table = ImRaii.Table("##files", 4, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, -Vector2.One);
if (!table) if (!table)
{
return; return;
}
var iconSize = ImGui.GetFrameHeight() * Vector2.One; var iconSize = ImGui.GetFrameHeight() * Vector2.One;
foreach (var (info, idx) in _editor.MdlMaterialEditor.ModelFiles.WithIndex()) foreach (var (info, idx) in _editor.MdlMaterialEditor.ModelFiles.WithIndex())
@ -219,16 +195,12 @@ public partial class ModEditWindow
ImGui.TableNextColumn(); ImGui.TableNextColumn();
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Save.ToIconString(), iconSize, if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Save.ToIconString(), iconSize,
"Save the changed mdl file.\nUse at own risk!", !info.Changed, true)) "Save the changed mdl file.\nUse at own risk!", !info.Changed, true))
{
info.Save(); info.Save();
}
ImGui.TableNextColumn(); ImGui.TableNextColumn();
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Recycle.ToIconString(), iconSize, if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Recycle.ToIconString(), iconSize,
"Restore current changes to default.", !info.Changed, true)) "Restore current changes to default.", !info.Changed, true))
{
info.Restore(); info.Restore();
}
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.TextUnformatted(info.Path.FullName[(_mod!.ModPath.FullName.Length + 1)..]); ImGui.TextUnformatted(info.Path.FullName[(_mod!.ModPath.FullName.Length + 1)..]);
@ -236,9 +208,7 @@ public partial class ModEditWindow
ImGui.SetNextItemWidth(400 * UiHelpers.Scale); ImGui.SetNextItemWidth(400 * UiHelpers.Scale);
var tmp = info.CurrentMaterials[0]; var tmp = info.CurrentMaterials[0];
if (ImGui.InputText("##0", ref tmp, 64)) if (ImGui.InputText("##0", ref tmp, 64))
{
info.SetMaterial(tmp, 0); info.SetMaterial(tmp, 0);
}
for (var i = 1; i < info.Count; ++i) for (var i = 1; i < info.Count; ++i)
{ {
@ -249,10 +219,8 @@ public partial class ModEditWindow
ImGui.SetNextItemWidth(400 * UiHelpers.Scale); ImGui.SetNextItemWidth(400 * UiHelpers.Scale);
tmp = info.CurrentMaterials[i]; tmp = info.CurrentMaterials[i];
if (ImGui.InputText($"##{i}", ref tmp, 64)) if (ImGui.InputText($"##{i}", ref tmp, 64))
{
info.SetMaterial(tmp, i); info.SetMaterial(tmp, i);
} }
} }
} }
} }
}

View file

@ -5,7 +5,6 @@ using Penumbra.GameData.Files;
using Penumbra.String.Classes; using Penumbra.String.Classes;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using Penumbra.UI.AdvancedWindow;
namespace Penumbra.UI.AdvancedWindow; namespace Penumbra.UI.AdvancedWindow;

View file

@ -71,9 +71,7 @@ public partial class ModEditWindow
private static void DrawShaderExportButton(ShpkTab tab, string objectName, Shader shader, int idx) private static void DrawShaderExportButton(ShpkTab tab, string objectName, Shader shader, int idx)
{ {
if (!ImGui.Button($"Export Shader Program Blob ({shader.Blob.Length} bytes)")) if (!ImGui.Button($"Export Shader Program Blob ({shader.Blob.Length} bytes)"))
{
return; return;
}
var defaultName = objectName[0] switch var defaultName = objectName[0] switch
{ {
@ -83,12 +81,11 @@ public partial class ModEditWindow
}; };
var blob = shader.Blob; var blob = shader.Blob;
tab.FileDialog.OpenSavePicker( $"Export {objectName} #{idx} Program Blob to...", tab.Extension, defaultName, tab.Extension, ( success, name ) => tab.FileDialog.OpenSavePicker($"Export {objectName} #{idx} Program Blob to...", tab.Extension, defaultName, tab.Extension,
(success, name) =>
{ {
if (!success) if (!success)
{
return; return;
}
try try
{ {
@ -96,12 +93,14 @@ public partial class ModEditWindow
} }
catch (Exception e) catch (Exception e)
{ {
Penumbra.Chat.NotificationMessage( $"Could not export {defaultName}{tab.Extension} to {name}:\n{e.Message}", "Penumbra Advanced Editing", Penumbra.Chat.NotificationMessage($"Could not export {defaultName}{tab.Extension} to {name}:\n{e.Message}",
"Penumbra Advanced Editing",
NotificationType.Error); NotificationType.Error);
return; return;
} }
Penumbra.Chat.NotificationMessage( $"Shader Program Blob {defaultName}{tab.Extension} exported successfully to {Path.GetFileName( name )}", Penumbra.Chat.NotificationMessage(
$"Shader Program Blob {defaultName}{tab.Extension} exported successfully to {Path.GetFileName(name)}",
"Penumbra Advanced Editing", NotificationType.Success); "Penumbra Advanced Editing", NotificationType.Success);
}, null, false); }, null, false);
} }
@ -109,16 +108,13 @@ public partial class ModEditWindow
private static void DrawShaderImportButton(ShpkTab tab, string objectName, Shader[] shaders, int idx) private static void DrawShaderImportButton(ShpkTab tab, string objectName, Shader[] shaders, int idx)
{ {
if (!ImGui.Button("Replace Shader Program Blob")) if (!ImGui.Button("Replace Shader Program Blob"))
{
return; return;
}
tab.FileDialog.OpenFilePicker( $"Replace {objectName} #{idx} Program Blob...", "Shader Program Blobs{.o,.cso,.dxbc,.dxil}", ( success, name ) => tab.FileDialog.OpenFilePicker($"Replace {objectName} #{idx} Program Blob...", "Shader Program Blobs{.o,.cso,.dxbc,.dxil}",
(success, name) =>
{ {
if (!success) if (!success)
{
return; return;
}
try try
{ {
@ -126,7 +122,8 @@ public partial class ModEditWindow
} }
catch (Exception e) catch (Exception e)
{ {
Penumbra.Chat.NotificationMessage( $"Could not import {name}:\n{e.Message}", "Penumbra Advanced Editing", NotificationType.Error ); Penumbra.Chat.NotificationMessage($"Could not import {name}:\n{e.Message}", "Penumbra Advanced Editing",
NotificationType.Error);
return; return;
} }
@ -138,7 +135,8 @@ public partial class ModEditWindow
catch (Exception e) catch (Exception e)
{ {
tab.Shpk.SetInvalid(); tab.Shpk.SetInvalid();
Penumbra.Chat.NotificationMessage( $"Failed to update resources after importing {name}:\n{e.Message}", "Penumbra Advanced Editing", Penumbra.Chat.NotificationMessage($"Failed to update resources after importing {name}:\n{e.Message}",
"Penumbra Advanced Editing",
NotificationType.Error); NotificationType.Error);
return; return;
} }
@ -151,22 +149,19 @@ public partial class ModEditWindow
{ {
using var t2 = ImRaii.TreeNode("Raw Program Disassembly"); using var t2 = ImRaii.TreeNode("Raw Program Disassembly");
if (!t2) if (!t2)
{
return; return;
}
using var font = ImRaii.PushFont(UiBuilder.MonoFont); using var font = ImRaii.PushFont(UiBuilder.MonoFont);
var size = new Vector2(ImGui.GetContentRegionAvail().X, ImGui.GetTextLineHeight() * 20); var size = new Vector2(ImGui.GetContentRegionAvail().X, ImGui.GetTextLineHeight() * 20);
ImGuiNative.igInputTextMultiline( DisassemblyLabel.Path, shader.Disassembly!.RawDisassembly.Path, ( uint )shader.Disassembly!.RawDisassembly.Length + 1, size, ImGuiNative.igInputTextMultiline(DisassemblyLabel.Path, shader.Disassembly!.RawDisassembly.Path,
(uint)shader.Disassembly!.RawDisassembly.Length + 1, size,
ImGuiInputTextFlags.ReadOnly, null, null); ImGuiInputTextFlags.ReadOnly, null, null);
} }
private static bool DrawShaderPackageShaderArray(ShpkTab tab, string objectName, Shader[] shaders, bool disabled) private static bool DrawShaderPackageShaderArray(ShpkTab tab, string objectName, Shader[] shaders, bool disabled)
{ {
if (shaders.Length == 0 || !ImGui.CollapsingHeader($"{objectName}s")) if (shaders.Length == 0 || !ImGui.CollapsingHeader($"{objectName}s"))
{
return false; return false;
}
var ret = false; var ret = false;
for (var idx = 0; idx < shaders.Length; ++idx) for (var idx = 0; idx < shaders.Length; ++idx)
@ -174,9 +169,7 @@ public partial class ModEditWindow
var shader = shaders[idx]; var shader = shaders[idx];
using var t = ImRaii.TreeNode($"{objectName} #{idx}"); using var t = ImRaii.TreeNode($"{objectName} #{idx}");
if (!t) if (!t)
{
continue; continue;
}
DrawShaderExportButton(tab, objectName, shader, idx); DrawShaderExportButton(tab, objectName, shader, idx);
if (!disabled && tab.Shpk.Disassembled) if (!disabled && tab.Shpk.Disassembled)
@ -193,10 +186,8 @@ public partial class ModEditWindow
{ {
using var t2 = ImRaii.TreeNode($"Additional Header (Size: {shader.AdditionalHeader.Length})###AdditionalHeader"); using var t2 = ImRaii.TreeNode($"Additional Header (Size: {shader.AdditionalHeader.Length})###AdditionalHeader");
if (t2) if (t2)
{
ImGuiUtil.TextWrapped(string.Join(' ', shader.AdditionalHeader.Select(c => $"{c:X2}"))); ImGuiUtil.TextWrapped(string.Join(' ', shader.AdditionalHeader.Select(c => $"{c:X2}")));
} }
}
if (tab.Shpk.Disassembled) if (tab.Shpk.Disassembled)
DrawRawDisassembly(shader); DrawRawDisassembly(shader);
@ -212,25 +203,17 @@ public partial class ModEditWindow
{ {
ImGui.SetNextItemWidth(UiHelpers.Scale * 150.0f); ImGui.SetNextItemWidth(UiHelpers.Scale * 150.0f);
if (ImGuiUtil.InputUInt16($"{char.ToUpper(slotLabel[0])}{slotLabel[1..].ToLower()}", ref resource.Slot, ImGuiInputTextFlags.None)) if (ImGuiUtil.InputUInt16($"{char.ToUpper(slotLabel[0])}{slotLabel[1..].ToLower()}", ref resource.Slot, ImGuiInputTextFlags.None))
{
ret = true; ret = true;
} }
}
if (resource.Used == null) if (resource.Used == null)
{
return ret; return ret;
}
var usedString = UsedComponentString(withSize, resource); var usedString = UsedComponentString(withSize, resource);
if (usedString.Length > 0) if (usedString.Length > 0)
{
ImRaii.TreeNode($"Used: {usedString}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); ImRaii.TreeNode($"Used: {usedString}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
}
else else
{
ImRaii.TreeNode("Unused", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); ImRaii.TreeNode("Unused", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
}
return ret; return ret;
} }
@ -238,15 +221,11 @@ public partial class ModEditWindow
private static bool DrawShaderPackageResourceArray(string arrayName, string slotLabel, bool withSize, Resource[] resources, bool disabled) private static bool DrawShaderPackageResourceArray(string arrayName, string slotLabel, bool withSize, Resource[] resources, bool disabled)
{ {
if (resources.Length == 0) if (resources.Length == 0)
{
return false; return false;
}
using var t = ImRaii.TreeNode(arrayName); using var t = ImRaii.TreeNode(arrayName);
if (!t) if (!t)
{
return false; return false;
}
var ret = false; var ret = false;
for (var idx = 0; idx < resources.Length; ++idx) for (var idx = 0; idx < resources.Length; ++idx)
@ -258,10 +237,8 @@ public partial class ModEditWindow
using var t2 = ImRaii.TreeNode(name, !disabled || buf.Used != null ? 0 : ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet); using var t2 = ImRaii.TreeNode(name, !disabled || buf.Used != null ? 0 : ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet);
font.Dispose(); font.Dispose();
if (t2) if (t2)
{
ret |= DrawShaderPackageResource(slotLabel, withSize, ref buf, disabled); ret |= DrawShaderPackageResource(slotLabel, withSize, ref buf, disabled);
} }
}
return ret; return ret;
} }
@ -270,20 +247,21 @@ public partial class ModEditWindow
{ {
using var font = ImRaii.PushFont(UiBuilder.MonoFont); using var font = ImRaii.PushFont(UiBuilder.MonoFont);
var pos = ImGui.GetCursorScreenPos() var pos = ImGui.GetCursorScreenPos()
+ new Vector2( ImGui.CalcTextSize( label ).X + 3 * ImGui.GetStyle().ItemInnerSpacing.X + ImGui.GetFrameHeight(), ImGui.GetStyle().FramePadding.Y ); + new Vector2(ImGui.CalcTextSize(label).X + 3 * ImGui.GetStyle().ItemInnerSpacing.X + ImGui.GetFrameHeight(),
ImGui.GetStyle().FramePadding.Y);
var ret = ImGui.CollapsingHeader(label); var ret = ImGui.CollapsingHeader(label);
ImGui.GetWindowDrawList().AddText( UiBuilder.DefaultFont, UiBuilder.DefaultFont.FontSize, pos, ImGui.GetColorU32( ImGuiCol.Text ), "Layout" ); ImGui.GetWindowDrawList()
.AddText(UiBuilder.DefaultFont, UiBuilder.DefaultFont.FontSize, pos, ImGui.GetColorU32(ImGuiCol.Text), "Layout");
return ret; return ret;
} }
private static bool DrawMaterialParamLayoutBufferSize(ShpkFile file, Resource? materialParams) private static bool DrawMaterialParamLayoutBufferSize(ShpkFile file, Resource? materialParams)
{ {
var isSizeWellDefined = ( file.MaterialParamsSize & 0xF ) == 0 && ( !materialParams.HasValue || file.MaterialParamsSize == materialParams.Value.Size << 4 ); var isSizeWellDefined = (file.MaterialParamsSize & 0xF) == 0
&& (!materialParams.HasValue || file.MaterialParamsSize == materialParams.Value.Size << 4);
if (isSizeWellDefined) if (isSizeWellDefined)
{
return true; return true;
}
ImGui.TextUnformatted(materialParams.HasValue ImGui.TextUnformatted(materialParams.HasValue
? $"Buffer size mismatch: {file.MaterialParamsSize} bytes ≠ {materialParams.Value.Size} registers ({materialParams.Value.Size << 4} bytes)" ? $"Buffer size mismatch: {file.MaterialParamsSize} bytes ≠ {materialParams.Value.Size} registers ({materialParams.Value.Size << 4} bytes)"
@ -300,9 +278,7 @@ public partial class ModEditWindow
using var table = ImRaii.Table("##MaterialParamLayout", 5, using var table = ImRaii.Table("##MaterialParamLayout", 5,
ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg); ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg);
if (!table) if (!table)
{
return false; return false;
}
ImGui.TableSetupColumn(string.Empty, ImGuiTableColumnFlags.WidthFixed, 25 * UiHelpers.Scale); ImGui.TableSetupColumn(string.Empty, ImGuiTableColumnFlags.WidthFixed, 25 * UiHelpers.Scale);
ImGui.TableSetupColumn("x", ImGuiTableColumnFlags.WidthFixed, 100 * UiHelpers.Scale); ImGui.TableSetupColumn("x", ImGuiTableColumnFlags.WidthFixed, 100 * UiHelpers.Scale);
@ -352,11 +328,9 @@ public partial class ModEditWindow
} }
if (deletable) if (deletable)
{
ImGuiUtil.HoverTooltip("\nControl + Right-Click to remove."); ImGuiUtil.HoverTooltip("\nControl + Right-Click to remove.");
} }
} }
}
return ret; return ret;
} }
@ -365,16 +339,12 @@ public partial class ModEditWindow
{ {
using var t = ImRaii.TreeNode("Misaligned / Overflowing Parameters"); using var t = ImRaii.TreeNode("Misaligned / Overflowing Parameters");
if (!t) if (!t)
{
return; return;
}
using var _ = ImRaii.PushFont(UiBuilder.MonoFont); using var _ = ImRaii.PushFont(UiBuilder.MonoFont);
foreach (var name in tab.MalformedParameters) foreach (var name in tab.MalformedParameters)
{
ImRaii.TreeNode(name, ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); ImRaii.TreeNode(name, ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
} }
}
private static void DrawShaderPackageStartCombo(ShpkTab tab) private static void DrawShaderPackageStartCombo(ShpkTab tab)
{ {
@ -384,16 +354,12 @@ public partial class ModEditWindow
ImGui.SetNextItemWidth(UiHelpers.Scale * 400); ImGui.SetNextItemWidth(UiHelpers.Scale * 400);
using var c = ImRaii.Combo("##Start", tab.Orphans[tab.NewMaterialParamStart].Name); using var c = ImRaii.Combo("##Start", tab.Orphans[tab.NewMaterialParamStart].Name);
if (c) if (c)
{
foreach (var (start, idx) in tab.Orphans.WithIndex()) foreach (var (start, idx) in tab.Orphans.WithIndex())
{ {
if (ImGui.Selectable(start.Name, idx == tab.NewMaterialParamStart)) if (ImGui.Selectable(start.Name, idx == tab.NewMaterialParamStart))
{
tab.UpdateOrphanStart(idx); tab.UpdateOrphanStart(idx);
} }
} }
}
}
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextUnformatted("Start"); ImGui.TextUnformatted("Start");
@ -413,17 +379,13 @@ public partial class ModEditWindow
{ {
var next = tab.Orphans[i]; var next = tab.Orphans[i];
if (current++ != next.Index) if (current++ != next.Index)
{
break; break;
}
if (ImGui.Selectable(next.Name, i == tab.NewMaterialParamEnd)) if (ImGui.Selectable(next.Name, i == tab.NewMaterialParamEnd))
{
tab.NewMaterialParamEnd = i; tab.NewMaterialParamEnd = i;
} }
} }
} }
}
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextUnformatted("End"); ImGui.TextUnformatted("End");
@ -432,27 +394,22 @@ public partial class ModEditWindow
private static bool DrawShaderPackageNewParameter(ShpkTab tab) private static bool DrawShaderPackageNewParameter(ShpkTab tab)
{ {
if (tab.Orphans.Count == 0) if (tab.Orphans.Count == 0)
{
return false; return false;
}
DrawShaderPackageStartCombo(tab); DrawShaderPackageStartCombo(tab);
DrawShaderPackageEndCombo(tab); DrawShaderPackageEndCombo(tab);
ImGui.SetNextItemWidth(UiHelpers.Scale * 400); ImGui.SetNextItemWidth(UiHelpers.Scale * 400);
if (ImGui.InputText("Name", ref tab.NewMaterialParamName, 63)) if (ImGui.InputText("Name", ref tab.NewMaterialParamName, 63))
{
tab.NewMaterialParamId = Crc32.Get(tab.NewMaterialParamName, 0xFFFFFFFFu); tab.NewMaterialParamId = Crc32.Get(tab.NewMaterialParamName, 0xFFFFFFFFu);
}
var tooltip = tab.UsedIds.Contains(tab.NewMaterialParamId) var tooltip = tab.UsedIds.Contains(tab.NewMaterialParamId)
? "The ID is already in use. Please choose a different name." ? "The ID is already in use. Please choose a different name."
: string.Empty; : string.Empty;
if( !ImGuiUtil.DrawDisabledButton( $"Add ID 0x{tab.NewMaterialParamId:X8}", new Vector2( 400 * UiHelpers.Scale, ImGui.GetFrameHeight() ), tooltip, if (!ImGuiUtil.DrawDisabledButton($"Add ID 0x{tab.NewMaterialParamId:X8}", new Vector2(400 * UiHelpers.Scale, ImGui.GetFrameHeight()),
tooltip,
tooltip.Length > 0)) tooltip.Length > 0))
{
return false; return false;
}
tab.Shpk.MaterialParams = tab.Shpk.MaterialParams.AddItem(new MaterialParam tab.Shpk.MaterialParams = tab.Shpk.MaterialParams.AddItem(new MaterialParam
{ {
@ -470,22 +427,16 @@ public partial class ModEditWindow
var materialParams = tab.Shpk.GetConstantById(MaterialParamsConstantId); var materialParams = tab.Shpk.GetConstantById(MaterialParamsConstantId);
if (!DrawMaterialParamLayoutHeader(materialParams?.Name ?? "Material Parameter")) if (!DrawMaterialParamLayoutHeader(materialParams?.Name ?? "Material Parameter"))
{
return false; return false;
}
var sizeWellDefined = DrawMaterialParamLayoutBufferSize(tab.Shpk, materialParams); var sizeWellDefined = DrawMaterialParamLayoutBufferSize(tab.Shpk, materialParams);
ret |= DrawShaderPackageMaterialMatrix(tab, disabled); ret |= DrawShaderPackageMaterialMatrix(tab, disabled);
if (tab.MalformedParameters.Count > 0) if (tab.MalformedParameters.Count > 0)
{
DrawShaderPackageMisalignedParameters(tab); DrawShaderPackageMisalignedParameters(tab);
}
else if (!disabled && sizeWellDefined) else if (!disabled && sizeWellDefined)
{
ret |= DrawShaderPackageNewParameter(tab); ret |= DrawShaderPackageNewParameter(tab);
}
return ret; return ret;
} }
@ -495,9 +446,7 @@ public partial class ModEditWindow
var ret = false; var ret = false;
if (!ImGui.CollapsingHeader("Shader Resources")) if (!ImGui.CollapsingHeader("Shader Resources"))
{
return false; return false;
}
ret |= DrawShaderPackageResourceArray("Constant Buffers", "type", true, tab.Shpk.Constants, disabled); ret |= DrawShaderPackageResourceArray("Constant Buffers", "type", true, tab.Shpk.Constants, disabled);
ret |= DrawShaderPackageResourceArray("Samplers", "type", false, tab.Shpk.Samplers, disabled); ret |= DrawShaderPackageResourceArray("Samplers", "type", false, tab.Shpk.Samplers, disabled);
@ -509,15 +458,11 @@ public partial class ModEditWindow
private static void DrawKeyArray(string arrayName, bool withId, IReadOnlyCollection<Key> keys) private static void DrawKeyArray(string arrayName, bool withId, IReadOnlyCollection<Key> keys)
{ {
if (keys.Count == 0) if (keys.Count == 0)
{
return; return;
}
using var t = ImRaii.TreeNode(arrayName); using var t = ImRaii.TreeNode(arrayName);
if (!t) if (!t)
{
return; return;
}
using var font = ImRaii.PushFont(UiBuilder.MonoFont); using var font = ImRaii.PushFont(UiBuilder.MonoFont);
foreach (var (key, idx) in keys.WithIndex()) foreach (var (key, idx) in keys.WithIndex())
@ -535,46 +480,36 @@ public partial class ModEditWindow
private static void DrawShaderPackageNodes(ShpkTab tab) private static void DrawShaderPackageNodes(ShpkTab tab)
{ {
if (tab.Shpk.Nodes.Length <= 0) if (tab.Shpk.Nodes.Length <= 0)
{
return; return;
}
using var t = ImRaii.TreeNode($"Nodes ({tab.Shpk.Nodes.Length})###Nodes"); using var t = ImRaii.TreeNode($"Nodes ({tab.Shpk.Nodes.Length})###Nodes");
if (!t) if (!t)
{
return; return;
}
foreach (var (node, idx) in tab.Shpk.Nodes.WithIndex()) foreach (var (node, idx) in tab.Shpk.Nodes.WithIndex())
{ {
using var font = ImRaii.PushFont(UiBuilder.MonoFont); using var font = ImRaii.PushFont(UiBuilder.MonoFont);
using var t2 = ImRaii.TreeNode($"#{idx:D4}: Selector: 0x{node.Selector:X8}"); using var t2 = ImRaii.TreeNode($"#{idx:D4}: Selector: 0x{node.Selector:X8}");
if (!t2) if (!t2)
{
continue; continue;
}
foreach (var (key, keyIdx) in node.SystemKeys.WithIndex()) foreach (var (key, keyIdx) in node.SystemKeys.WithIndex())
{ ImRaii.TreeNode($"System Key 0x{tab.Shpk.SystemKeys[keyIdx].Id:X8} = 0x{key:X8}",
ImRaii.TreeNode( $"System Key 0x{tab.Shpk.SystemKeys[ keyIdx ].Id:X8} = 0x{key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet ).Dispose(); ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
}
foreach (var (key, keyIdx) in node.SceneKeys.WithIndex()) foreach (var (key, keyIdx) in node.SceneKeys.WithIndex())
{ ImRaii.TreeNode($"Scene Key 0x{tab.Shpk.SceneKeys[keyIdx].Id:X8} = 0x{key:X8}",
ImRaii.TreeNode( $"Scene Key 0x{tab.Shpk.SceneKeys[ keyIdx ].Id:X8} = 0x{key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet ).Dispose(); ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
}
foreach (var (key, keyIdx) in node.MaterialKeys.WithIndex()) foreach (var (key, keyIdx) in node.MaterialKeys.WithIndex())
{ ImRaii.TreeNode($"Material Key 0x{tab.Shpk.MaterialKeys[keyIdx].Id:X8} = 0x{key:X8}",
ImRaii.TreeNode( $"Material Key 0x{tab.Shpk.MaterialKeys[ keyIdx ].Id:X8} = 0x{key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet ).Dispose(); ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
}
foreach (var (key, keyIdx) in node.SubViewKeys.WithIndex()) foreach (var (key, keyIdx) in node.SubViewKeys.WithIndex())
{
ImRaii.TreeNode($"Sub-View Key #{keyIdx} = 0x{key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); ImRaii.TreeNode($"Sub-View Key #{keyIdx} = 0x{key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
}
ImRaii.TreeNode( $"Pass Indices: {string.Join( ' ', node.PassIndices.Select( c => $"{c:X2}" ) )}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet ).Dispose(); ImRaii.TreeNode($"Pass Indices: {string.Join(' ', node.PassIndices.Select(c => $"{c:X2}"))}",
ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
foreach (var (pass, passIdx) in node.Passes.WithIndex()) foreach (var (pass, passIdx) in node.Passes.WithIndex())
{ {
ImRaii.TreeNode($"Pass #{passIdx}: ID: 0x{pass.Id:X8}, Vertex Shader #{pass.VertexShader}, Pixel Shader #{pass.PixelShader}", ImRaii.TreeNode($"Pass #{passIdx}: ID: 0x{pass.Id:X8}, Vertex Shader #{pass.VertexShader}, Pixel Shader #{pass.PixelShader}",
@ -587,9 +522,7 @@ public partial class ModEditWindow
private static void DrawShaderPackageSelection(ShpkTab tab) private static void DrawShaderPackageSelection(ShpkTab tab)
{ {
if (!ImGui.CollapsingHeader("Shader Selection")) if (!ImGui.CollapsingHeader("Shader Selection"))
{
return; return;
}
DrawKeyArray("System Keys", true, tab.Shpk.SystemKeys); DrawKeyArray("System Keys", true, tab.Shpk.SystemKeys);
DrawKeyArray("Scene Keys", true, tab.Shpk.SceneKeys); DrawKeyArray("Scene Keys", true, tab.Shpk.SceneKeys);
@ -602,18 +535,15 @@ public partial class ModEditWindow
{ {
using var font = ImRaii.PushFont(UiBuilder.MonoFont); using var font = ImRaii.PushFont(UiBuilder.MonoFont);
foreach (var selector in tab.Shpk.NodeSelectors) foreach (var selector in tab.Shpk.NodeSelectors)
{ ImRaii.TreeNode($"#{selector.Value:D4}: Selector: 0x{selector.Key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet)
ImRaii.TreeNode( $"#{selector.Value:D4}: Selector: 0x{selector.Key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet ).Dispose(); .Dispose();
}
} }
} }
private static void DrawOtherShaderPackageDetails(ShpkTab tab) private static void DrawOtherShaderPackageDetails(ShpkTab tab)
{ {
if (!ImGui.CollapsingHeader("Further Content")) if (!ImGui.CollapsingHeader("Further Content"))
{
return; return;
}
ImRaii.TreeNode($"Version: 0x{tab.Shpk.Version:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); ImRaii.TreeNode($"Version: 0x{tab.Shpk.Version:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
@ -621,11 +551,9 @@ public partial class ModEditWindow
{ {
using var t = ImRaii.TreeNode($"Additional Data (Size: {tab.Shpk.AdditionalData.Length})###AdditionalData"); using var t = ImRaii.TreeNode($"Additional Data (Size: {tab.Shpk.AdditionalData.Length})###AdditionalData");
if (t) if (t)
{
ImGuiUtil.TextWrapped(string.Join(' ', tab.Shpk.AdditionalData.Select(c => $"{c:X2}"))); ImGuiUtil.TextWrapped(string.Join(' ', tab.Shpk.AdditionalData.Select(c => $"{c:X2}")));
} }
} }
}
private static string UsedComponentString(bool withSize, in Resource resource) private static string UsedComponentString(bool withSize, in Resource resource)
{ {
@ -643,9 +571,7 @@ public partial class ModEditWindow
default: default:
sb.Append($"[{i}]."); sb.Append($"[{i}].");
foreach (var c in components.ToString().Where(char.IsUpper)) foreach (var c in components.ToString().Where(char.IsUpper))
{
sb.Append(char.ToLower(c)); sb.Append(char.ToLower(c));
}
sb.Append(", "); sb.Append(", ");
break; break;
@ -661,9 +587,7 @@ public partial class ModEditWindow
default: default:
sb.Append("[*]."); sb.Append("[*].");
foreach (var c in resource.UsedDynamically!.Value.ToString().Where(char.IsUpper)) foreach (var c in resource.UsedDynamically!.Value.ToString().Where(char.IsUpper))
{
sb.Append(char.ToLower(c)); sb.Append(char.ToLower(c));
}
sb.Append(", "); sb.Append(", ");
break; break;
@ -673,25 +597,17 @@ public partial class ModEditWindow
{ {
var components = (resource.Used is { Length: > 0 } ? resource.Used[0] : 0) | (resource.UsedDynamically ?? 0); var components = (resource.Used is { Length: > 0 } ? resource.Used[0] : 0) | (resource.UsedDynamically ?? 0);
if ((components & DisassembledShader.VectorComponents.X) != 0) if ((components & DisassembledShader.VectorComponents.X) != 0)
{
sb.Append("Red, "); sb.Append("Red, ");
}
if ((components & DisassembledShader.VectorComponents.Y) != 0) if ((components & DisassembledShader.VectorComponents.Y) != 0)
{
sb.Append("Green, "); sb.Append("Green, ");
}
if ((components & DisassembledShader.VectorComponents.Z) != 0) if ((components & DisassembledShader.VectorComponents.Z) != 0)
{
sb.Append("Blue, "); sb.Append("Blue, ");
}
if ((components & DisassembledShader.VectorComponents.W) != 0) if ((components & DisassembledShader.VectorComponents.W) != 0)
{
sb.Append("Alpha, "); sb.Append("Alpha, ");
} }
}
return sb.Length == 0 ? string.Empty : sb.ToString(0, sb.Length - 2); return sb.Length == 0 ? string.Empty : sb.ToString(0, sb.Length - 2);
} }

View file

@ -533,14 +533,20 @@ public partial class ModEditWindow : Window, IDisposable
var ret = new HashSet<Utf8GamePath>(); var ret = new HashSet<Utf8GamePath>();
foreach (var path in _activeCollections.Current.ResolvedFiles.Keys) foreach (var path in _activeCollections.Current.ResolvedFiles.Keys)
{
if (path.Path.StartsWith(prefix)) if (path.Path.StartsWith(prefix))
ret.Add(path); ret.Add(path);
}
if (_mod != null) if (_mod != null)
foreach (var option in _mod.Groups.SelectMany(g => g).Append(_mod.Default)) foreach (var option in _mod.Groups.SelectMany(g => g).Append(_mod.Default))
{
foreach (var path in option.Files.Keys) foreach (var path in option.Files.Keys)
{
if (path.Path.StartsWith(prefix)) if (path.Path.StartsWith(prefix))
ret.Add(path); ret.Add(path);
}
}
return ret; return ret;
} }