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)
{
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));

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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