mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Auto-formatting and some cleanup.
This commit is contained in:
parent
ff01276869
commit
e5e555b981
8 changed files with 876 additions and 959 deletions
|
|
@ -20,15 +20,11 @@ public partial class ModEditWindow
|
|||
private bool DrawMaterialColorSetChange(MtrlTab tab, bool disabled)
|
||||
{
|
||||
if (!tab.SamplerIds.Contains(ShpkFile.TableSamplerId) || !tab.Mtrl.ColorSets.Any(c => c.HasRows))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
||||
if (!ImGui.CollapsingHeader("Color Set", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var hasAnyDye = tab.UseColorDyeSet;
|
||||
|
||||
|
|
@ -42,6 +38,7 @@ public partial class ModEditWindow
|
|||
ImGui.SameLine();
|
||||
ret |= ColorSetDyeableCheckbox(tab, ref hasAnyDye);
|
||||
}
|
||||
|
||||
if (hasAnyDye)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
|
|
@ -53,9 +50,7 @@ public partial class ModEditWindow
|
|||
using var table = ImRaii.Table("##ColorSets", hasAnyDye ? 11 : 9,
|
||||
ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg | ImGuiTableFlags.BordersInnerV);
|
||||
if (!table)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TableHeader(string.Empty);
|
||||
|
|
@ -100,9 +95,7 @@ public partial class ModEditWindow
|
|||
private static void ColorSetCopyAllClipboardButton(MtrlFile file, int colorSetIdx)
|
||||
{
|
||||
if (!ImGui.Button("Export All Rows to Clipboard", ImGuiHelpers.ScaledVector2(200, 0)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -123,17 +116,17 @@ public partial class ModEditWindow
|
|||
private bool DrawPreviewDye(MtrlTab tab, bool disabled)
|
||||
{
|
||||
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))
|
||||
{
|
||||
var ret = false;
|
||||
for (var j = 0; j < tab.Mtrl.ColorDyeSets.Length; ++j)
|
||||
{
|
||||
for (var i = 0; i < MtrlFile.ColorSet.RowArray.NumRows; ++i)
|
||||
{
|
||||
ret |= tab.Mtrl.ApplyDyeTemplate(_stainService.StmFile, j, i, dyeId);
|
||||
}
|
||||
}
|
||||
|
||||
tab.UpdateColorSetPreview();
|
||||
|
||||
|
|
@ -149,19 +142,16 @@ public partial class ModEditWindow
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var text = ImGui.GetClipboardText();
|
||||
var data = Convert.FromBase64String(text);
|
||||
if (data.Length < Marshal.SizeOf<MtrlFile.ColorSet.RowArray>())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ref var rows = ref tab.Mtrl.ColorSets[colorSetIdx].Rows;
|
||||
fixed (void* ptr = data, output = &rows)
|
||||
|
|
@ -173,7 +163,8 @@ public partial class ModEditWindow
|
|||
ref var dyeRows = ref tab.Mtrl.ColorDyeSets[colorSetIdx].Rows;
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var data = new byte[MtrlFile.ColorSet.Row.Size + 2];
|
||||
|
|
@ -210,7 +202,6 @@ public partial class ModEditWindow
|
|||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
var text = ImGui.GetClipboardText();
|
||||
var data = Convert.FromBase64String(text);
|
||||
if (data.Length != MtrlFile.ColorSet.Row.Size + 2
|
||||
|| tab.Mtrl.ColorSets.Length <= colorSetIdx)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
tab.Mtrl.ColorSets[colorSetIdx].Rows[rowIdx] = *(MtrlFile.ColorSet.Row*)ptr;
|
||||
if (colorSetIdx < tab.Mtrl.ColorDyeSets.Length)
|
||||
{
|
||||
tab.Mtrl.ColorDyeSets[colorSetIdx].Rows[rowIdx] = *(MtrlFile.ColorDyeSet.Row*)(ptr + MtrlFile.ColorSet.Row.Size);
|
||||
}
|
||||
}
|
||||
|
||||
tab.UpdateColorSetRowPreview(rowIdx);
|
||||
|
||||
|
|
@ -257,12 +245,9 @@ public partial class ModEditWindow
|
|||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ColorSetHighlightButton(MtrlTab tab, int rowIdx, bool disabled)
|
||||
{
|
||||
|
|
@ -301,16 +286,28 @@ public partial class ModEditWindow
|
|||
|
||||
ImGui.TableNextColumn();
|
||||
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)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
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();
|
||||
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();
|
||||
var tmpFloat = row.SpecularStrength;
|
||||
ImGui.SetNextItemWidth(floatSize);
|
||||
|
|
@ -327,25 +324,42 @@ public partial class ModEditWindow
|
|||
{
|
||||
ImGui.SameLine();
|
||||
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();
|
||||
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();
|
||||
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)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
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();
|
||||
tmpFloat = row.GlossStrength;
|
||||
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);
|
||||
ret = true;
|
||||
|
|
@ -357,7 +371,11 @@ public partial class ModEditWindow
|
|||
{
|
||||
ImGui.SameLine();
|
||||
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();
|
||||
|
|
@ -375,7 +393,8 @@ public partial class ModEditWindow
|
|||
ImGui.TableNextColumn();
|
||||
tmpFloat = row.MaterialRepeat.X;
|
||||
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 };
|
||||
ret = true;
|
||||
|
|
@ -386,7 +405,8 @@ public partial class ModEditWindow
|
|||
ImGui.SameLine();
|
||||
tmpFloat = row.MaterialRepeat.Y;
|
||||
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 };
|
||||
ret = true;
|
||||
|
|
@ -449,9 +469,7 @@ public partial class ModEditWindow
|
|||
{
|
||||
var stain = _stainService.StainCombo.CurrentSelection.Key;
|
||||
if (stain == 0 || !_stainService.StmFile.Entries.TryGetValue(dye.Template, out var entry))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var values = entry[(int)stain];
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemSpacing / 2);
|
||||
|
|
@ -486,7 +504,11 @@ public partial class ModEditWindow
|
|||
var inputSqrt = PseudoSqrtRgb(input);
|
||||
var tmp = inputSqrt;
|
||||
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)
|
||||
{
|
||||
setter(PseudoSquareRgb(tmp));
|
||||
|
|
@ -509,7 +531,7 @@ public partial class ModEditWindow
|
|||
// Functions to deal with squared RGB values without making negatives useless.
|
||||
|
||||
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)
|
||||
=> new(PseudoSquareRgb(vec.X), PseudoSquareRgb(vec.Y), PseudoSquareRgb(vec.Z));
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
using ImGuiNET;
|
||||
using OtterGui.Raii;
|
||||
|
|
@ -27,7 +28,8 @@ public partial class ModEditWindow
|
|||
private readonly float _bias;
|
||||
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;
|
||||
_maximum = maximum;
|
||||
|
|
@ -55,10 +57,13 @@ public partial class ModEditWindow
|
|||
|
||||
var value = (values[valueIdx] - _bias) / _factor;
|
||||
if (disabled)
|
||||
{
|
||||
ImGui.DragFloat($"##{valueIdx}", ref value, Math.Max(_speed, value * _relativeSpeed), value, value, _format);
|
||||
}
|
||||
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;
|
||||
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);
|
||||
if (disabled)
|
||||
{
|
||||
ImGui.DragInt($"##{valueIdx}", ref value, Math.Max(_speed, value * _relativeSpeed), value, value, _format);
|
||||
}
|
||||
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;
|
||||
ret = true;
|
||||
|
|
@ -142,14 +150,17 @@ public partial class ModEditWindow
|
|||
|
||||
public bool Draw(Span<float> values, bool disabled, float editorWidth)
|
||||
{
|
||||
if (values.Length == 3)
|
||||
switch (values.Length)
|
||||
{
|
||||
case 3:
|
||||
{
|
||||
ImGui.SetNextItemWidth(editorWidth);
|
||||
var value = new Vector3(values);
|
||||
if (_squaredRgb)
|
||||
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)
|
||||
value = PseudoSquareRgb(value);
|
||||
if (_clamped)
|
||||
|
|
@ -157,17 +168,17 @@ public partial class ModEditWindow
|
|||
value.CopyTo(values);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else if (values.Length == 4)
|
||||
case 4:
|
||||
{
|
||||
ImGui.SetNextItemWidth(editorWidth);
|
||||
var value = new Vector4(values);
|
||||
if (_squaredRgb)
|
||||
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)
|
||||
value = PseudoSquareRgb(value);
|
||||
if (_clamped)
|
||||
|
|
@ -175,11 +186,8 @@ public partial class ModEditWindow
|
|||
value.CopyTo(values);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
default: return FloatConstantEditor.Default.Draw(values, disabled, editorWidth);
|
||||
}
|
||||
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;
|
||||
|
||||
public EnumConstantEditor(IReadOnlyList<(string Label, float Value, string Description)> values)
|
||||
{
|
||||
_values = values;
|
||||
}
|
||||
=> _values = values;
|
||||
|
||||
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)
|
||||
{
|
||||
using var id = ImRaii.PushId(valueIdx);
|
||||
if (valueIdx > 0)
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGui.SetNextItemWidth(MathF.Round(fieldWidth * (valueIdx + 1)) - MathF.Round(fieldWidth * valueIdx));
|
||||
|
||||
var currentValue = values[valueIdx];
|
||||
var (currentLabel, _, currentDescription) = _values.FirstOrNull(v => v.Value == currentValue) ?? (currentValue.ToString(), currentValue, string.Empty);
|
||||
if (disabled)
|
||||
ImGui.InputText($"##{valueIdx}", ref currentLabel, (uint)currentLabel.Length, ImGuiInputTextFlags.ReadOnly);
|
||||
else
|
||||
var currentLabel = _values.FirstOrNull(v => v.Value == currentValue)?.Label
|
||||
?? currentValue.ToString(CultureInfo.CurrentCulture);
|
||||
ret = disabled
|
||||
? 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);
|
||||
{
|
||||
if (c)
|
||||
using var c = ImRaii.Combo(string.Empty, label);
|
||||
if (!c)
|
||||
return false;
|
||||
|
||||
var ret = false;
|
||||
foreach (var (valueLabel, value, valueDescription) in _values)
|
||||
{
|
||||
if (ImGui.Selectable(valueLabel, value == currentValue))
|
||||
{
|
||||
values[valueIdx] = value;
|
||||
currentValue = value;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (valueDescription.Length > 0)
|
||||
ImGuiUtil.SelectableHelpMarker(valueDescription);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ using System.Linq;
|
|||
using System.Numerics;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Internal.Notifications;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using ImGuiNET;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
|
@ -17,10 +16,8 @@ using Penumbra.GameData;
|
|||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.String;
|
||||
using Penumbra.String.Classes;
|
||||
using Penumbra.Util;
|
||||
using static Penumbra.GameData.Files.ShpkFile;
|
||||
|
||||
namespace Penumbra.UI.AdvancedWindow;
|
||||
|
|
@ -48,15 +45,17 @@ public partial class ModEditWindow
|
|||
public ShpkFile? AssociatedShpk;
|
||||
public JObject? AssociatedShpkDevkit;
|
||||
|
||||
public readonly string LoadedBaseDevkitPathName = string.Empty;
|
||||
public readonly string LoadedBaseDevkitPathName;
|
||||
public readonly JObject? AssociatedBaseDevkit;
|
||||
|
||||
// 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> PixelShaders = new(16);
|
||||
public bool ShadersKnown = false;
|
||||
public bool ShadersKnown;
|
||||
public string VertexShadersString = "Vertex Shaders: ???";
|
||||
public string PixelShadersString = "Pixel Shaders: ???";
|
||||
|
||||
|
|
@ -69,7 +68,9 @@ public partial class ModEditWindow
|
|||
public bool UseColorDyeSet;
|
||||
|
||||
// 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
|
||||
public readonly List<LiveMaterialPreviewer> MaterialPreviewers = new(4);
|
||||
|
|
@ -81,9 +82,7 @@ public partial class ModEditWindow
|
|||
{
|
||||
defaultPath = GamePaths.Shader.ShpkPath(Mtrl.ShaderPackage.Name);
|
||||
if (!Utf8GamePath.FromString(defaultPath, out defaultGamePath, true))
|
||||
{
|
||||
return FullPath.Empty;
|
||||
}
|
||||
|
||||
return _edit.FindBestMatch(defaultGamePath);
|
||||
}
|
||||
|
|
@ -120,7 +119,8 @@ public partial class ModEditWindow
|
|||
LoadedShpkPath = FullPath.Empty;
|
||||
LoadedShpkPathName = string.Empty;
|
||||
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)
|
||||
|
|
@ -129,7 +129,10 @@ public partial class ModEditWindow
|
|||
LoadedShpkDevkitPathName = string.Empty;
|
||||
}
|
||||
else
|
||||
AssociatedShpkDevkit = TryLoadShpkDevkit( Path.GetFileNameWithoutExtension( Mtrl.ShaderPackage.Name ), out LoadedShpkDevkitPathName );
|
||||
{
|
||||
AssociatedShpkDevkit =
|
||||
TryLoadShpkDevkit(Path.GetFileNameWithoutExtension(Mtrl.ShaderPackage.Name), out LoadedShpkDevkitPathName);
|
||||
}
|
||||
|
||||
UpdateShaderKeys();
|
||||
Update();
|
||||
|
|
@ -157,10 +160,8 @@ public partial class ModEditWindow
|
|||
}
|
||||
|
||||
private T? TryGetShpkDevkitData<T>(string category, uint? id, bool mayVary) where T : class
|
||||
{
|
||||
return TryGetShpkDevkitData<T>(AssociatedShpkDevkit, LoadedShpkDevkitPathName, category, id, mayVary)
|
||||
=> TryGetShpkDevkitData<T>(AssociatedShpkDevkit, LoadedShpkDevkitPathName, 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
|
||||
{
|
||||
|
|
@ -175,7 +176,7 @@ public partial class ModEditWindow
|
|||
|
||||
if (mayVary && (data as JObject)?["Vary"] != null)
|
||||
{
|
||||
var selector = BuildSelector(data!["Vary"]!
|
||||
var selector = BuildSelector(data["Vary"]!
|
||||
.Select(key => (uint)key)
|
||||
.Select(key => Mtrl.GetShaderKey(key)?.Value ?? AssociatedShpk!.GetMaterialKeyById(key)!.Value.DefaultValue));
|
||||
var index = (int)data["Selectors"]![selector.ToString()]!;
|
||||
|
|
@ -192,11 +193,10 @@ public partial class ModEditWindow
|
|||
}
|
||||
}
|
||||
|
||||
public void UpdateShaderKeys()
|
||||
private void UpdateShaderKeys()
|
||||
{
|
||||
ShaderKeys.Clear();
|
||||
if (AssociatedShpk != null)
|
||||
{
|
||||
foreach (var key in AssociatedShpk.MaterialKeys)
|
||||
{
|
||||
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))
|
||||
return (dkValue.Label.Length > 0 ? dkValue.Label : $"0x{value:X8}", value, dkValue.Description);
|
||||
else
|
||||
|
||||
return ($"0x{value:X8}", value, string.Empty);
|
||||
}).ToArray();
|
||||
Array.Sort(values, (x, y) =>
|
||||
|
|
@ -220,31 +220,33 @@ public partial class ModEditWindow
|
|||
return -1;
|
||||
if (y.Value == key.DefaultValue)
|
||||
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
|
||||
{
|
||||
foreach (var (key, index) in Mtrl.ShaderPackage.ShaderKeys.WithIndex())
|
||||
ShaderKeys.Add(($"0x{key.Category:X8}", index, string.Empty, true, Array.Empty<(string, uint, string)>()));
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateShaders()
|
||||
private void UpdateShaders()
|
||||
{
|
||||
VertexShaders.Clear();
|
||||
PixelShaders.Clear();
|
||||
if (AssociatedShpk == null)
|
||||
{
|
||||
ShadersKnown = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
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));
|
||||
var materialKeySelector =
|
||||
BuildSelector(AssociatedShpk.MaterialKeys.Select(key => Mtrl.GetOrAddShaderKey(key.Id, key.DefaultValue).Value));
|
||||
foreach (var systemKeySelector in systemKeySelectors)
|
||||
{
|
||||
foreach (var sceneKeySelector in sceneKeySelectors)
|
||||
|
|
@ -254,13 +256,11 @@ public partial class ModEditWindow
|
|||
var selector = BuildSelector(systemKeySelector, sceneKeySelector, materialKeySelector, subViewKeySelector);
|
||||
var node = AssociatedShpk.GetNodeBySelector(selector);
|
||||
if (node.HasValue)
|
||||
{
|
||||
foreach (var pass in node.Value.Passes)
|
||||
{
|
||||
VertexShaders.Add((int)pass.VertexShader);
|
||||
PixelShaders.Add((int)pass.PixelShader);
|
||||
}
|
||||
}
|
||||
else
|
||||
ShadersKnown = false;
|
||||
}
|
||||
|
|
@ -277,7 +277,7 @@ public partial class ModEditWindow
|
|||
ShaderComment = TryGetShpkDevkitData<string>("Comment", null, true) ?? string.Empty;
|
||||
}
|
||||
|
||||
public void UpdateTextures()
|
||||
private void UpdateTextures()
|
||||
{
|
||||
Textures.Clear();
|
||||
SamplerIds.Clear();
|
||||
|
|
@ -302,50 +302,63 @@ public partial class ModEditWindow
|
|||
if (Mtrl.ColorSets.Any(c => c.HasRows))
|
||||
SamplerIds.Add(TableSamplerId);
|
||||
}
|
||||
|
||||
foreach (var samplerId in SamplerIds)
|
||||
{
|
||||
var shpkSampler = AssociatedShpk.GetSamplerById(samplerId);
|
||||
if (!shpkSampler.HasValue || shpkSampler.Value.Slot != 2)
|
||||
if (shpkSampler is not { Slot: 2 })
|
||||
continue;
|
||||
|
||||
var dkData = TryGetShpkDevkitData<DevkitSampler>("Samplers", samplerId, true);
|
||||
var hasDkLabel = !string.IsNullOrEmpty(dkData?.Label);
|
||||
|
||||
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))
|
||||
Mtrl.FindOrAddColorSet();
|
||||
}
|
||||
|
||||
Textures.Sort((x, y) => string.CompareOrdinal(x.Label, y.Label));
|
||||
|
||||
TextureLabelWidth = 50f * UiHelpers.Scale;
|
||||
|
||||
float helpWidth;
|
||||
using (var _ = ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
helpWidth = ImGui.GetStyle().ItemSpacing.X + ImGui.CalcTextSize(FontAwesomeIcon.InfoCircle.ToIconString()).X;
|
||||
}
|
||||
|
||||
foreach (var (label, _, _, description, monoFont) in Textures)
|
||||
{
|
||||
if (!monoFont)
|
||||
TextureLabelWidth = Math.Max(TextureLabelWidth, ImGui.CalcTextSize(label).X + (description.Length > 0 ? helpWidth : 0.0f));
|
||||
}
|
||||
|
||||
using (var _ = ImRaii.PushFont(UiBuilder.MonoFont))
|
||||
{
|
||||
foreach (var (label, _, _, description, monoFont) in Textures)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
public void UpdateConstants()
|
||||
private void UpdateConstants()
|
||||
{
|
||||
static List<T> FindOrAddGroup<T>(List<(string, List<T>)> groups, string name)
|
||||
{
|
||||
foreach (var (groupName, group) in groups)
|
||||
{
|
||||
if (string.Equals(name, groupName, StringComparison.Ordinal))
|
||||
return group;
|
||||
}
|
||||
|
||||
var newGroup = new List<T>(16);
|
||||
groups.Add((name, newGroup));
|
||||
|
|
@ -360,7 +373,10 @@ public partial class ModEditWindow
|
|||
{
|
||||
var values = Mtrl.GetConstantValues(constant);
|
||||
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
|
||||
|
|
@ -377,7 +393,6 @@ public partial class ModEditWindow
|
|||
|
||||
var dkData = TryGetShpkDevkitData<DevkitConstant[]>("Constants", shpkConstant.Id, true);
|
||||
if (dkData != null)
|
||||
{
|
||||
foreach (var dkConstant in dkData)
|
||||
{
|
||||
var offset = (int)dkConstant.Offset;
|
||||
|
|
@ -386,13 +401,13 @@ public partial class ModEditWindow
|
|||
length = Math.Min(length, (int)dkConstant.Length.Value);
|
||||
if (length <= 0)
|
||||
continue;
|
||||
|
||||
var editor = dkConstant.CreateEditor();
|
||||
if (editor != null)
|
||||
FindOrAddGroup(Constants, dkConstant.Group.Length > 0 ? dkConstant.Group : "Further Constants")
|
||||
.Add((dkConstant.Label, constantIndex, offset..(offset + length), dkConstant.Description, false, editor));
|
||||
handledElements.AddRange(offset, length);
|
||||
}
|
||||
}
|
||||
|
||||
var fcGroup = FindOrAddGroup(Constants, "Further Constants");
|
||||
foreach (var (start, end) in handledElements.Ranges(true))
|
||||
|
|
@ -405,13 +420,18 @@ public partial class ModEditWindow
|
|||
var rangeStart = Math.Max(i, start);
|
||||
var rangeEnd = Math.Min(i + 4, end);
|
||||
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
|
||||
{
|
||||
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;
|
||||
if (string.Equals(y.Header, "Further Constants", StringComparison.Ordinal))
|
||||
return -1;
|
||||
|
||||
return string.Compare(x.Header, y.Header, StringComparison.Ordinal);
|
||||
});
|
||||
// HACK the Replace makes w appear after xyz, for the cbuffer-location-based naming scheme
|
||||
foreach (var (_, group) in Constants)
|
||||
{
|
||||
group.Sort((x, y) => string.CompareOrdinal(
|
||||
x.MonoFont ? x.Label.Replace("].w", "].{") : x.Label,
|
||||
y.MonoFont ? y.Label.Replace("].w", "].{") : y.Label));
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe void BindToMaterialInstances()
|
||||
{
|
||||
UnbindFromMaterialInstances();
|
||||
|
||||
var localPlayer = FindLocalPlayer(_edit._dalamud.Objects);
|
||||
var localPlayer = LocalPlayer(_edit._dalamud.Objects);
|
||||
if (null == localPlayer)
|
||||
return;
|
||||
|
||||
|
|
@ -449,7 +472,9 @@ public partial class ModEditWindow
|
|||
|
||||
var drawObjects = stackalloc CharacterBase*[4];
|
||||
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)
|
||||
{
|
||||
var subActor = FindSubActor(localPlayer, i);
|
||||
|
|
@ -470,9 +495,11 @@ public partial class ModEditWindow
|
|||
var material = GetDrawObjectMaterial(drawObjects[subActorType + 1], modelSlot, materialSlot);
|
||||
if (foundMaterials.Contains((nint)material))
|
||||
continue;
|
||||
|
||||
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);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
|
|
@ -480,28 +507,31 @@ public partial class ModEditWindow
|
|||
// Carry on without that previewer.
|
||||
}
|
||||
}
|
||||
|
||||
UpdateMaterialPreview();
|
||||
|
||||
var colorSet = Mtrl.ColorSets.FirstOrNull(colorSet => colorSet.HasRows);
|
||||
|
||||
if (colorSet.HasValue)
|
||||
{
|
||||
if (!colorSet.HasValue)
|
||||
return;
|
||||
|
||||
foreach (var (subActorType, childObjectIndex, modelSlot, materialSlot) in instances)
|
||||
{
|
||||
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)
|
||||
{
|
||||
// Carry on without that previewer.
|
||||
}
|
||||
}
|
||||
|
||||
UpdateColorSetPreview();
|
||||
}
|
||||
}
|
||||
|
||||
public void UnbindFromMaterialInstances()
|
||||
private void UnbindFromMaterialInstances()
|
||||
{
|
||||
foreach (var previewer in MaterialPreviewers)
|
||||
previewer.Dispose();
|
||||
|
|
@ -512,7 +542,7 @@ public partial class ModEditWindow
|
|||
ColorSetPreviewers.Clear();
|
||||
}
|
||||
|
||||
public unsafe void UnbindFromDrawObjectMaterialInstances(nint characterBase)
|
||||
private unsafe void UnbindFromDrawObjectMaterialInstances(nint characterBase)
|
||||
{
|
||||
for (var i = MaterialPreviewers.Count; i-- > 0;)
|
||||
{
|
||||
|
|
@ -553,7 +583,7 @@ public partial class ModEditWindow
|
|||
previewer.SetSamplerFlags(samplerCrc, samplerFlags);
|
||||
}
|
||||
|
||||
public void UpdateMaterialPreview()
|
||||
private void UpdateMaterialPreview()
|
||||
{
|
||||
SetShaderPackageFlags(Mtrl.ShaderPackage.Flags);
|
||||
foreach (var constant in Mtrl.ShaderPackage.Constants)
|
||||
|
|
@ -562,6 +592,7 @@ public partial class ModEditWindow
|
|||
if (values != null)
|
||||
SetMaterialParameter(constant.Id, 0, values);
|
||||
}
|
||||
|
||||
foreach (var sampler in Mtrl.ShaderPackage.Samplers)
|
||||
SetSamplerFlags(sampler.SamplerId, sampler.Flags);
|
||||
}
|
||||
|
|
@ -610,7 +641,7 @@ public partial class ModEditWindow
|
|||
{
|
||||
var stm = _edit._stainService.StmFile;
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -619,7 +650,8 @@ public partial class ModEditWindow
|
|||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
@ -694,18 +726,7 @@ public partial class ModEditWindow
|
|||
}
|
||||
}
|
||||
|
||||
~MtrlTab()
|
||||
{
|
||||
DoDispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DoDispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void DoDispose()
|
||||
{
|
||||
UnbindFromMaterialInstances();
|
||||
if (Writable)
|
||||
|
|
@ -723,11 +744,7 @@ public partial class ModEditWindow
|
|||
return output.Write();
|
||||
}
|
||||
|
||||
private sealed class DevkitShaderKeyValue
|
||||
{
|
||||
public string Label = string.Empty;
|
||||
public string Description = string.Empty;
|
||||
}
|
||||
private sealed record DevkitShaderKeyValue(string Label = "", string Description = "");
|
||||
|
||||
private sealed class DevkitShaderKey
|
||||
{
|
||||
|
|
@ -736,12 +753,7 @@ public partial class ModEditWindow
|
|||
public Dictionary<uint, DevkitShaderKeyValue> Values = new();
|
||||
}
|
||||
|
||||
private sealed class DevkitSampler
|
||||
{
|
||||
public string Label = string.Empty;
|
||||
public string Description = string.Empty;
|
||||
public string DefaultTexture = string.Empty;
|
||||
}
|
||||
private sealed record DevkitSampler(string Label = "", string Description = "", string DefaultTexture = "");
|
||||
|
||||
private enum DevkitConstantType
|
||||
{
|
||||
|
|
@ -752,12 +764,7 @@ public partial class ModEditWindow
|
|||
Enum = 3,
|
||||
}
|
||||
|
||||
private sealed class DevkitConstantValue
|
||||
{
|
||||
public string Label = string.Empty;
|
||||
public string Description = string.Empty;
|
||||
public float Value = 0.0f;
|
||||
}
|
||||
private sealed record DevkitConstantValue(string Label = "", string Description = "", float Value = 0);
|
||||
|
||||
private sealed class DevkitConstant
|
||||
{
|
||||
|
|
@ -783,25 +790,20 @@ public partial class ModEditWindow
|
|||
public DevkitConstantValue[] Values = Array.Empty<DevkitConstantValue>();
|
||||
|
||||
public IConstantEditor? CreateEditor()
|
||||
=> Type switch
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case DevkitConstantType.Hidden:
|
||||
return null;
|
||||
case DevkitConstantType.Float:
|
||||
return new FloatConstantEditor(Minimum, Maximum, Speed ?? 0.1f, RelativeSpeed, Factor, Bias, Precision, Unit);
|
||||
case DevkitConstantType.Integer:
|
||||
return new IntConstantEditor(ToInteger(Minimum), ToInteger(Maximum), Speed ?? 0.25f, RelativeSpeed, Factor, Bias, Unit);
|
||||
case DevkitConstantType.Color:
|
||||
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;
|
||||
}
|
||||
}
|
||||
DevkitConstantType.Hidden => null,
|
||||
DevkitConstantType.Float => new FloatConstantEditor(Minimum, Maximum, Speed ?? 0.1f, RelativeSpeed, Factor, Bias, Precision,
|
||||
Unit),
|
||||
DevkitConstantType.Integer => new IntConstantEditor(ToInteger(Minimum), ToInteger(Maximum), Speed ?? 0.25f, RelativeSpeed,
|
||||
Factor, Bias, Unit),
|
||||
DevkitConstantType.Color => new ColorConstantEditor(SquaredRgb, Clamped),
|
||||
DevkitConstantType.Enum => new EnumConstantEditor(Array.ConvertAll(Values,
|
||||
value => (value.Label, value.Value, value.Description))),
|
||||
_ => 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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.ImGuiFileDialog;
|
||||
using ImGuiNET;
|
||||
using Lumina.Data.Parsing;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.String.Classes;
|
||||
|
||||
namespace Penumbra.UI.AdvancedWindow;
|
||||
|
|
@ -25,7 +19,7 @@ public partial class ModEditWindow
|
|||
// Apricot shader packages are unlisted because
|
||||
// 1. they cause performance/memory issues when calculating the effective shader set
|
||||
// 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",
|
||||
// "apricot_decal_dummy.shpk",
|
||||
|
|
@ -76,7 +70,7 @@ public partial class ModEditWindow
|
|||
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.",
|
||||
"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)
|
||||
{
|
||||
var ret = false;
|
||||
var shpkFlags = (int)tab.Mtrl.ShaderPackage.Flags;
|
||||
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)))
|
||||
{
|
||||
tab.Mtrl.ShaderPackage.Flags = (uint)shpkFlags;
|
||||
ret = true;
|
||||
tab.SetShaderPackageFlags((uint)shpkFlags);
|
||||
}
|
||||
return false;
|
||||
|
||||
return ret;
|
||||
tab.Mtrl.ShaderPackage.Flags = (uint)shpkFlags;
|
||||
tab.SetShaderPackageFlags((uint)shpkFlags);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using OtterGui;
|
|||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.String.Classes;
|
||||
using Penumbra.UI.Classes;
|
||||
|
||||
namespace Penumbra.UI.AdvancedWindow;
|
||||
|
||||
|
|
@ -41,31 +42,23 @@ public partial class ModEditWindow
|
|||
if (ImGui.Button("Reload live preview"))
|
||||
tab.BindToMaterialInstances();
|
||||
|
||||
if (tab.MaterialPreviewers.Count == 0 && tab.ColorSetPreviewers.Count == 0)
|
||||
{
|
||||
if (tab.MaterialPreviewers.Count != 0 || tab.ColorSetPreviewers.Count != 0)
|
||||
return;
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
var textColor = ImGui.GetColorU32(ImGuiCol.Text);
|
||||
var textColorWarning = (textColor & 0xFF000000u) | ((textColor & 0x00FEFEFE) >> 1) | 0x80u; // Half red
|
||||
|
||||
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.");
|
||||
}
|
||||
using var c = ImRaii.PushColor(ImGuiCol.Text, Colors.RegexWarningBorder);
|
||||
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)
|
||||
{
|
||||
if (tab.Textures.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
||||
if (!ImGui.CollapsingHeader("Textures and Samplers", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var frameHeight = ImGui.GetFrameHeight();
|
||||
var ret = false;
|
||||
|
|
@ -74,15 +67,14 @@ public partial class ModEditWindow
|
|||
ImGui.TableSetupColumn(string.Empty, ImGuiTableColumnFlags.WidthFixed, frameHeight);
|
||||
ImGui.TableSetupColumn("Path", ImGuiTableColumnFlags.WidthStretch);
|
||||
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);
|
||||
var tmp = tab.Mtrl.Textures[textureI].Path;
|
||||
var unfolded = tab.UnfoldedTextures.Contains(samplerI);
|
||||
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))
|
||||
{
|
||||
unfolded = !unfolded;
|
||||
|
|
@ -91,6 +83,7 @@ public partial class ModEditWindow
|
|||
else
|
||||
tab.UnfoldedTextures.Remove(samplerI);
|
||||
}
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X);
|
||||
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;
|
||||
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;
|
||||
tab.SetShaderPackageFlags(tab.Mtrl.ShaderPackage.Flags);
|
||||
}
|
||||
|
|
@ -156,45 +150,31 @@ public partial class ModEditWindow
|
|||
private static void DrawOtherMaterialDetails(MtrlFile file, bool _)
|
||||
{
|
||||
if (!ImGui.CollapsingHeader("Further Content"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using (var sets = ImRaii.TreeNode("UV Sets", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
if (sets)
|
||||
{
|
||||
foreach (var set in file.UvSets)
|
||||
{
|
||||
ImRaii.TreeNode($"#{set.Index:D2} - {set.Name}", ImGuiTreeNodeFlags.Leaf).Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (file.AdditionalData.Length <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var t = ImRaii.TreeNode($"Additional Data (Size: {file.AdditionalData.Length})###AdditionalData");
|
||||
if (t)
|
||||
{
|
||||
ImGuiUtil.TextWrapped(string.Join(' ', file.AdditionalData.Select(c => $"{c:X2}")));
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawMaterialReassignmentTab()
|
||||
{
|
||||
if (_editor.Files.Mdl.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var tab = ImRaii.TabItem("Material Reassignment");
|
||||
if (!tab)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui.NewLine();
|
||||
MaterialSuffix.Draw(_editor, ImGuiHelpers.ScaledVector2(175, 0));
|
||||
|
|
@ -202,15 +182,11 @@ public partial class ModEditWindow
|
|||
ImGui.NewLine();
|
||||
using var child = ImRaii.Child("##mdlFiles", -Vector2.One, true);
|
||||
if (!child)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var table = ImRaii.Table("##files", 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())
|
||||
|
|
@ -219,16 +195,12 @@ public partial class ModEditWindow
|
|||
ImGui.TableNextColumn();
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Save.ToIconString(), iconSize,
|
||||
"Save the changed mdl file.\nUse at own risk!", !info.Changed, true))
|
||||
{
|
||||
info.Save();
|
||||
}
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Recycle.ToIconString(), iconSize,
|
||||
"Restore current changes to default.", !info.Changed, true))
|
||||
{
|
||||
info.Restore();
|
||||
}
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted(info.Path.FullName[(_mod!.ModPath.FullName.Length + 1)..]);
|
||||
|
|
@ -236,9 +208,7 @@ public partial class ModEditWindow
|
|||
ImGui.SetNextItemWidth(400 * UiHelpers.Scale);
|
||||
var tmp = info.CurrentMaterials[0];
|
||||
if (ImGui.InputText("##0", ref tmp, 64))
|
||||
{
|
||||
info.SetMaterial(tmp, 0);
|
||||
}
|
||||
|
||||
for (var i = 1; i < info.Count; ++i)
|
||||
{
|
||||
|
|
@ -249,10 +219,8 @@ public partial class ModEditWindow
|
|||
ImGui.SetNextItemWidth(400 * UiHelpers.Scale);
|
||||
tmp = info.CurrentMaterials[i];
|
||||
if (ImGui.InputText($"##{i}", ref tmp, 64))
|
||||
{
|
||||
info.SetMaterial(tmp, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,6 @@ using Penumbra.GameData.Files;
|
|||
using Penumbra.String.Classes;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Penumbra.UI.AdvancedWindow;
|
||||
|
||||
namespace Penumbra.UI.AdvancedWindow;
|
||||
|
||||
|
|
|
|||
|
|
@ -71,9 +71,7 @@ public partial class ModEditWindow
|
|||
private static void DrawShaderExportButton(ShpkTab tab, string objectName, Shader shader, int idx)
|
||||
{
|
||||
if (!ImGui.Button($"Export Shader Program Blob ({shader.Blob.Length} bytes)"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var defaultName = objectName[0] switch
|
||||
{
|
||||
|
|
@ -83,12 +81,11 @@ public partial class ModEditWindow
|
|||
};
|
||||
|
||||
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)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -96,12 +93,14 @@ public partial class ModEditWindow
|
|||
}
|
||||
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);
|
||||
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);
|
||||
}, null, false);
|
||||
}
|
||||
|
|
@ -109,16 +108,13 @@ public partial class ModEditWindow
|
|||
private static void DrawShaderImportButton(ShpkTab tab, string objectName, Shader[] shaders, int idx)
|
||||
{
|
||||
if (!ImGui.Button("Replace Shader Program Blob"))
|
||||
{
|
||||
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)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -126,7 +122,8 @@ public partial class ModEditWindow
|
|||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -138,7 +135,8 @@ public partial class ModEditWindow
|
|||
catch (Exception e)
|
||||
{
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
|
@ -151,22 +149,19 @@ public partial class ModEditWindow
|
|||
{
|
||||
using var t2 = ImRaii.TreeNode("Raw Program Disassembly");
|
||||
if (!t2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var font = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
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);
|
||||
}
|
||||
|
||||
private static bool DrawShaderPackageShaderArray(ShpkTab tab, string objectName, Shader[] shaders, bool disabled)
|
||||
{
|
||||
if (shaders.Length == 0 || !ImGui.CollapsingHeader($"{objectName}s"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var ret = false;
|
||||
for (var idx = 0; idx < shaders.Length; ++idx)
|
||||
|
|
@ -174,9 +169,7 @@ public partial class ModEditWindow
|
|||
var shader = shaders[idx];
|
||||
using var t = ImRaii.TreeNode($"{objectName} #{idx}");
|
||||
if (!t)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
DrawShaderExportButton(tab, objectName, shader, idx);
|
||||
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");
|
||||
if (t2)
|
||||
{
|
||||
ImGuiUtil.TextWrapped(string.Join(' ', shader.AdditionalHeader.Select(c => $"{c:X2}")));
|
||||
}
|
||||
}
|
||||
|
||||
if (tab.Shpk.Disassembled)
|
||||
DrawRawDisassembly(shader);
|
||||
|
|
@ -212,25 +203,17 @@ public partial class ModEditWindow
|
|||
{
|
||||
ImGui.SetNextItemWidth(UiHelpers.Scale * 150.0f);
|
||||
if (ImGuiUtil.InputUInt16($"{char.ToUpper(slotLabel[0])}{slotLabel[1..].ToLower()}", ref resource.Slot, ImGuiInputTextFlags.None))
|
||||
{
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (resource.Used == null)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
var usedString = UsedComponentString(withSize, resource);
|
||||
if (usedString.Length > 0)
|
||||
{
|
||||
ImRaii.TreeNode($"Used: {usedString}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
ImRaii.TreeNode("Unused", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -238,15 +221,11 @@ public partial class ModEditWindow
|
|||
private static bool DrawShaderPackageResourceArray(string arrayName, string slotLabel, bool withSize, Resource[] resources, bool disabled)
|
||||
{
|
||||
if (resources.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
using var t = ImRaii.TreeNode(arrayName);
|
||||
if (!t)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var ret = false;
|
||||
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);
|
||||
font.Dispose();
|
||||
if (t2)
|
||||
{
|
||||
ret |= DrawShaderPackageResource(slotLabel, withSize, ref buf, disabled);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -270,20 +247,21 @@ public partial class ModEditWindow
|
|||
{
|
||||
using var font = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ImGui.TextUnformatted(materialParams.HasValue
|
||||
? $"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,
|
||||
ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg);
|
||||
if (!table)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ImGui.TableSetupColumn(string.Empty, ImGuiTableColumnFlags.WidthFixed, 25 * UiHelpers.Scale);
|
||||
ImGui.TableSetupColumn("x", ImGuiTableColumnFlags.WidthFixed, 100 * UiHelpers.Scale);
|
||||
|
|
@ -352,11 +328,9 @@ public partial class ModEditWindow
|
|||
}
|
||||
|
||||
if (deletable)
|
||||
{
|
||||
ImGuiUtil.HoverTooltip("\nControl + Right-Click to remove.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -365,16 +339,12 @@ public partial class ModEditWindow
|
|||
{
|
||||
using var t = ImRaii.TreeNode("Misaligned / Overflowing Parameters");
|
||||
if (!t)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var _ = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
foreach (var name in tab.MalformedParameters)
|
||||
{
|
||||
ImRaii.TreeNode(name, ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawShaderPackageStartCombo(ShpkTab tab)
|
||||
{
|
||||
|
|
@ -384,16 +354,12 @@ public partial class ModEditWindow
|
|||
ImGui.SetNextItemWidth(UiHelpers.Scale * 400);
|
||||
using var c = ImRaii.Combo("##Start", tab.Orphans[tab.NewMaterialParamStart].Name);
|
||||
if (c)
|
||||
{
|
||||
foreach (var (start, idx) in tab.Orphans.WithIndex())
|
||||
{
|
||||
if (ImGui.Selectable(start.Name, idx == tab.NewMaterialParamStart))
|
||||
{
|
||||
tab.UpdateOrphanStart(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted("Start");
|
||||
|
|
@ -413,17 +379,13 @@ public partial class ModEditWindow
|
|||
{
|
||||
var next = tab.Orphans[i];
|
||||
if (current++ != next.Index)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (ImGui.Selectable(next.Name, i == tab.NewMaterialParamEnd))
|
||||
{
|
||||
tab.NewMaterialParamEnd = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted("End");
|
||||
|
|
@ -432,27 +394,22 @@ public partial class ModEditWindow
|
|||
private static bool DrawShaderPackageNewParameter(ShpkTab tab)
|
||||
{
|
||||
if (tab.Orphans.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DrawShaderPackageStartCombo(tab);
|
||||
DrawShaderPackageEndCombo(tab);
|
||||
|
||||
ImGui.SetNextItemWidth(UiHelpers.Scale * 400);
|
||||
if (ImGui.InputText("Name", ref tab.NewMaterialParamName, 63))
|
||||
{
|
||||
tab.NewMaterialParamId = Crc32.Get(tab.NewMaterialParamName, 0xFFFFFFFFu);
|
||||
}
|
||||
|
||||
var tooltip = tab.UsedIds.Contains(tab.NewMaterialParamId)
|
||||
? "The ID is already in use. Please choose a different name."
|
||||
: 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))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
tab.Shpk.MaterialParams = tab.Shpk.MaterialParams.AddItem(new MaterialParam
|
||||
{
|
||||
|
|
@ -470,22 +427,16 @@ public partial class ModEditWindow
|
|||
|
||||
var materialParams = tab.Shpk.GetConstantById(MaterialParamsConstantId);
|
||||
if (!DrawMaterialParamLayoutHeader(materialParams?.Name ?? "Material Parameter"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var sizeWellDefined = DrawMaterialParamLayoutBufferSize(tab.Shpk, materialParams);
|
||||
|
||||
ret |= DrawShaderPackageMaterialMatrix(tab, disabled);
|
||||
|
||||
if (tab.MalformedParameters.Count > 0)
|
||||
{
|
||||
DrawShaderPackageMisalignedParameters(tab);
|
||||
}
|
||||
else if (!disabled && sizeWellDefined)
|
||||
{
|
||||
ret |= DrawShaderPackageNewParameter(tab);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -495,9 +446,7 @@ public partial class ModEditWindow
|
|||
var ret = false;
|
||||
|
||||
if (!ImGui.CollapsingHeader("Shader Resources"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ret |= DrawShaderPackageResourceArray("Constant Buffers", "type", true, tab.Shpk.Constants, 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)
|
||||
{
|
||||
if (keys.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var t = ImRaii.TreeNode(arrayName);
|
||||
if (!t)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var font = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
foreach (var (key, idx) in keys.WithIndex())
|
||||
|
|
@ -535,46 +480,36 @@ public partial class ModEditWindow
|
|||
private static void DrawShaderPackageNodes(ShpkTab tab)
|
||||
{
|
||||
if (tab.Shpk.Nodes.Length <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var t = ImRaii.TreeNode($"Nodes ({tab.Shpk.Nodes.Length})###Nodes");
|
||||
if (!t)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var (node, idx) in tab.Shpk.Nodes.WithIndex())
|
||||
{
|
||||
using var font = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
using var t2 = ImRaii.TreeNode($"#{idx:D4}: Selector: 0x{node.Selector:X8}");
|
||||
if (!t2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var (key, keyIdx) in node.SystemKeys.WithIndex())
|
||||
{
|
||||
ImRaii.TreeNode( $"System Key 0x{tab.Shpk.SystemKeys[ keyIdx ].Id:X8} = 0x{key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet ).Dispose();
|
||||
}
|
||||
ImRaii.TreeNode($"System Key 0x{tab.Shpk.SystemKeys[keyIdx].Id:X8} = 0x{key:X8}",
|
||||
ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
|
||||
|
||||
foreach (var (key, keyIdx) in node.SceneKeys.WithIndex())
|
||||
{
|
||||
ImRaii.TreeNode( $"Scene Key 0x{tab.Shpk.SceneKeys[ keyIdx ].Id:X8} = 0x{key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet ).Dispose();
|
||||
}
|
||||
ImRaii.TreeNode($"Scene Key 0x{tab.Shpk.SceneKeys[keyIdx].Id:X8} = 0x{key:X8}",
|
||||
ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
|
||||
|
||||
foreach (var (key, keyIdx) in node.MaterialKeys.WithIndex())
|
||||
{
|
||||
ImRaii.TreeNode( $"Material Key 0x{tab.Shpk.MaterialKeys[ keyIdx ].Id:X8} = 0x{key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet ).Dispose();
|
||||
}
|
||||
ImRaii.TreeNode($"Material Key 0x{tab.Shpk.MaterialKeys[keyIdx].Id:X8} = 0x{key:X8}",
|
||||
ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
|
||||
|
||||
foreach (var (key, keyIdx) in node.SubViewKeys.WithIndex())
|
||||
{
|
||||
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())
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (!ImGui.CollapsingHeader("Shader Selection"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DrawKeyArray("System Keys", true, tab.Shpk.SystemKeys);
|
||||
DrawKeyArray("Scene Keys", true, tab.Shpk.SceneKeys);
|
||||
|
|
@ -602,18 +535,15 @@ public partial class ModEditWindow
|
|||
{
|
||||
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 ).Dispose();
|
||||
}
|
||||
ImRaii.TreeNode($"#{selector.Value:D4}: Selector: 0x{selector.Key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet)
|
||||
.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawOtherShaderPackageDetails(ShpkTab tab)
|
||||
{
|
||||
if (!ImGui.CollapsingHeader("Further Content"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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");
|
||||
if (t)
|
||||
{
|
||||
ImGuiUtil.TextWrapped(string.Join(' ', tab.Shpk.AdditionalData.Select(c => $"{c:X2}")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string UsedComponentString(bool withSize, in Resource resource)
|
||||
{
|
||||
|
|
@ -643,9 +571,7 @@ public partial class ModEditWindow
|
|||
default:
|
||||
sb.Append($"[{i}].");
|
||||
foreach (var c in components.ToString().Where(char.IsUpper))
|
||||
{
|
||||
sb.Append(char.ToLower(c));
|
||||
}
|
||||
|
||||
sb.Append(", ");
|
||||
break;
|
||||
|
|
@ -661,9 +587,7 @@ public partial class ModEditWindow
|
|||
default:
|
||||
sb.Append("[*].");
|
||||
foreach (var c in resource.UsedDynamically!.Value.ToString().Where(char.IsUpper))
|
||||
{
|
||||
sb.Append(char.ToLower(c));
|
||||
}
|
||||
|
||||
sb.Append(", ");
|
||||
break;
|
||||
|
|
@ -673,25 +597,17 @@ public partial class ModEditWindow
|
|||
{
|
||||
var components = (resource.Used is { Length: > 0 } ? resource.Used[0] : 0) | (resource.UsedDynamically ?? 0);
|
||||
if ((components & DisassembledShader.VectorComponents.X) != 0)
|
||||
{
|
||||
sb.Append("Red, ");
|
||||
}
|
||||
|
||||
if ((components & DisassembledShader.VectorComponents.Y) != 0)
|
||||
{
|
||||
sb.Append("Green, ");
|
||||
}
|
||||
|
||||
if ((components & DisassembledShader.VectorComponents.Z) != 0)
|
||||
{
|
||||
sb.Append("Blue, ");
|
||||
}
|
||||
|
||||
if ((components & DisassembledShader.VectorComponents.W) != 0)
|
||||
{
|
||||
sb.Append("Alpha, ");
|
||||
}
|
||||
}
|
||||
|
||||
return sb.Length == 0 ? string.Empty : sb.ToString(0, sb.Length - 2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -533,14 +533,20 @@ public partial class ModEditWindow : Window, IDisposable
|
|||
var ret = new HashSet<Utf8GamePath>();
|
||||
|
||||
foreach (var path in _activeCollections.Current.ResolvedFiles.Keys)
|
||||
{
|
||||
if (path.Path.StartsWith(prefix))
|
||||
ret.Add(path);
|
||||
}
|
||||
|
||||
if (_mod != null)
|
||||
foreach (var option in _mod.Groups.SelectMany(g => g).Append(_mod.Default))
|
||||
{
|
||||
foreach (var path in option.Files.Keys)
|
||||
{
|
||||
if (path.Path.StartsWith(prefix))
|
||||
ret.Add(path);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue