mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Fix some off-by-one errors with the import progress reports, add test implementation for pbd editing.
This commit is contained in:
parent
2e424a693d
commit
4a0c996ff6
7 changed files with 368 additions and 20 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit 34c96a55efe1ce1296d9edcd8296f6396998cc6a
|
||||
Subproject commit 07b01ec9b043e4b8f56d084f5d6cde1ed4ed9a58
|
||||
|
|
@ -9,7 +9,6 @@ using Penumbra.Api.Api;
|
|||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Api.IpcSubscribers;
|
||||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Mods.Manager;
|
||||
using Penumbra.Services;
|
||||
|
|
@ -28,6 +27,8 @@ public class TemporaryIpcTester(
|
|||
{
|
||||
public Guid LastCreatedCollectionId = Guid.Empty;
|
||||
|
||||
private readonly bool _debug = Assembly.GetAssembly(typeof(TemporaryIpcTester))?.GetName().Version?.Major >= 9;
|
||||
|
||||
private Guid? _tempGuid;
|
||||
private string _tempCollectionName = string.Empty;
|
||||
private string _tempCollectionGuidName = string.Empty;
|
||||
|
|
@ -48,9 +49,9 @@ public class TemporaryIpcTester(
|
|||
ImGui.InputTextWithHint("##tempCollection", "Collection Name...", ref _tempCollectionName, 128);
|
||||
ImGuiUtil.GuidInput("##guid", "Collection GUID...", string.Empty, ref _tempGuid, ref _tempCollectionGuidName);
|
||||
ImGui.InputInt("##tempActorIndex", ref _tempActorIndex, 0, 0);
|
||||
ImGui.InputTextWithHint("##tempMod", "Temporary Mod Name...", ref _tempModName, 32);
|
||||
ImGui.InputTextWithHint("##tempGame", "Game Path...", ref _tempGamePath, 256);
|
||||
ImGui.InputTextWithHint("##tempFile", "File Path...", ref _tempFilePath, 256);
|
||||
ImGui.InputTextWithHint("##tempMod", "Temporary Mod Name...", ref _tempModName, 32);
|
||||
ImGui.InputTextWithHint("##tempGame", "Game Path...", ref _tempGamePath, 256);
|
||||
ImGui.InputTextWithHint("##tempFile", "File Path...", ref _tempFilePath, 256);
|
||||
ImUtf8.InputText("##tempManip"u8, ref _tempManipulation, "Manipulation Base64 String..."u8);
|
||||
ImGui.Checkbox("Force Character Collection Overwrite", ref _forceOverwrite);
|
||||
|
||||
|
|
@ -102,7 +103,7 @@ public class TemporaryIpcTester(
|
|||
!collections.Storage.ByName(_tempModName, out var copyCollection))
|
||||
&& copyCollection is { HasCache: true })
|
||||
{
|
||||
var files = copyCollection.ResolvedFiles.ToDictionary(kvp => kvp.Key.ToString(), kvp => kvp.Value.Path.ToString());
|
||||
var files = copyCollection.ResolvedFiles.ToDictionary(kvp => kvp.Key.ToString(), kvp => kvp.Value.Path.ToString());
|
||||
var manips = MetaApi.CompressMetaManipulations(copyCollection);
|
||||
_lastTempError = new AddTemporaryMod(pi).Invoke(_tempModName, guid, files, manips, 999);
|
||||
}
|
||||
|
|
@ -124,11 +125,11 @@ public class TemporaryIpcTester(
|
|||
|
||||
public void DrawCollections()
|
||||
{
|
||||
using var collTree = ImRaii.TreeNode("Temporary Collections##TempCollections");
|
||||
using var collTree = ImUtf8.TreeNode("Temporary Collections##TempCollections"u8);
|
||||
if (!collTree)
|
||||
return;
|
||||
|
||||
using var table = ImRaii.Table("##collTree", 6, ImGuiTableFlags.SizingFixedFit);
|
||||
using var table = ImUtf8.Table("##collTree"u8, 6, ImGuiTableFlags.SizingFixedFit);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
|
|
@ -139,7 +140,7 @@ public class TemporaryIpcTester(
|
|||
var character = tempCollections.Collections.Where(p => p.Collection == collection).Select(p => p.DisplayName)
|
||||
.FirstOrDefault()
|
||||
?? "Unknown";
|
||||
if (ImGui.Button("Save##Collection"))
|
||||
if (_debug && ImUtf8.Button("Save##Collection"u8))
|
||||
TemporaryMod.SaveTempCollection(config, saveService, modManager, collection, character);
|
||||
|
||||
using (ImRaii.PushFont(UiBuilder.MonoFont))
|
||||
|
|
|
|||
|
|
@ -46,21 +46,28 @@ public partial class TexToolsImporter
|
|||
{
|
||||
ImGui.NewLine();
|
||||
ImGui.NewLine();
|
||||
percentage = _currentNumOptions == 0 ? 1f : _currentOptionIdx / (float)_currentNumOptions;
|
||||
ImGui.ProgressBar(percentage, size, $"Option {_currentOptionIdx + 1} / {_currentNumOptions}");
|
||||
if (_currentOptionIdx >= _currentNumOptions)
|
||||
ImGui.ProgressBar(1f, size, $"Extracted {_currentNumOptions} Options");
|
||||
else
|
||||
ImGui.ProgressBar(_currentOptionIdx / (float)_currentNumOptions, size,
|
||||
$"Extracting Option {_currentOptionIdx + 1} / {_currentNumOptions}...");
|
||||
|
||||
ImGui.NewLine();
|
||||
if (State != ImporterState.DeduplicatingFiles)
|
||||
ImGui.TextUnformatted(
|
||||
$"Extracting option {(_currentGroupName.Length == 0 ? string.Empty : $"{_currentGroupName} - ")}{_currentOptionName}...");
|
||||
$"Extracting Option {(_currentGroupName.Length == 0 ? string.Empty : $"{_currentGroupName} - ")}{_currentOptionName}...");
|
||||
}
|
||||
|
||||
ImGui.NewLine();
|
||||
ImGui.NewLine();
|
||||
percentage = _currentNumFiles == 0 ? 1f : _currentFileIdx / (float)_currentNumFiles;
|
||||
ImGui.ProgressBar(percentage, size, $"File {_currentFileIdx + 1} / {_currentNumFiles}");
|
||||
if (_currentFileIdx >= _currentNumFiles)
|
||||
ImGui.ProgressBar(1f, size, $"Extracted {_currentNumFiles} Files");
|
||||
else
|
||||
ImGui.ProgressBar(_currentFileIdx / (float)_currentNumFiles, size, $"Extracting File {_currentFileIdx + 1} / {_currentNumFiles}...");
|
||||
|
||||
ImGui.NewLine();
|
||||
if (State != ImporterState.DeduplicatingFiles)
|
||||
ImGui.TextUnformatted($"Extracting file {_currentFileName}...");
|
||||
ImGui.TextUnformatted($"Extracting File {_currentFileName}...");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ public partial class TexToolsImporter
|
|||
_currentGroupName = string.Empty;
|
||||
_currentOptionName = "Default";
|
||||
ExtractSimpleModList(_currentModDirectory, modList.SimpleModsList);
|
||||
++_currentOptionIdx;
|
||||
}
|
||||
|
||||
// Iterate through all pages
|
||||
|
|
@ -208,6 +209,7 @@ public partial class TexToolsImporter
|
|||
options.Insert(idx, MultiSubMod.WithoutGroup(option.Name, option.Description, ModPriority.Default));
|
||||
if (option.IsChecked)
|
||||
defaultSettings = Setting.Single(idx);
|
||||
++_currentOptionIdx;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ public class ModFileCollection : IDisposable, IService
|
|||
private readonly List<FileRegistry> _mdl = [];
|
||||
private readonly List<FileRegistry> _tex = [];
|
||||
private readonly List<FileRegistry> _shpk = [];
|
||||
private readonly List<FileRegistry> _pbd = [];
|
||||
|
||||
private readonly SortedSet<FullPath> _missing = [];
|
||||
private readonly HashSet<Utf8GamePath> _usedPaths = [];
|
||||
|
|
@ -23,19 +24,22 @@ public class ModFileCollection : IDisposable, IService
|
|||
=> Ready ? _usedPaths : [];
|
||||
|
||||
public IReadOnlyList<FileRegistry> Available
|
||||
=> Ready ? _available : Array.Empty<FileRegistry>();
|
||||
=> Ready ? _available : [];
|
||||
|
||||
public IReadOnlyList<FileRegistry> Mtrl
|
||||
=> Ready ? _mtrl : Array.Empty<FileRegistry>();
|
||||
=> Ready ? _mtrl : [];
|
||||
|
||||
public IReadOnlyList<FileRegistry> Mdl
|
||||
=> Ready ? _mdl : Array.Empty<FileRegistry>();
|
||||
=> Ready ? _mdl : [];
|
||||
|
||||
public IReadOnlyList<FileRegistry> Tex
|
||||
=> Ready ? _tex : Array.Empty<FileRegistry>();
|
||||
=> Ready ? _tex : [];
|
||||
|
||||
public IReadOnlyList<FileRegistry> Shpk
|
||||
=> Ready ? _shpk : Array.Empty<FileRegistry>();
|
||||
=> Ready ? _shpk : [];
|
||||
|
||||
public IReadOnlyList<FileRegistry> Pbd
|
||||
=> Ready ? _pbd : [];
|
||||
|
||||
public bool Ready { get; private set; } = true;
|
||||
|
||||
|
|
@ -128,6 +132,9 @@ public class ModFileCollection : IDisposable, IService
|
|||
case ".shpk":
|
||||
_shpk.Add(registry);
|
||||
break;
|
||||
case ".pbd":
|
||||
_pbd.Add(registry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -139,6 +146,7 @@ public class ModFileCollection : IDisposable, IService
|
|||
_mdl.Clear();
|
||||
_tex.Clear();
|
||||
_shpk.Clear();
|
||||
_pbd.Clear();
|
||||
}
|
||||
|
||||
private void ClearPaths(bool clearRegistries, CancellationToken tok)
|
||||
|
|
|
|||
324
Penumbra/UI/AdvancedWindow/ModEditWindow.Deformers.cs
Normal file
324
Penumbra/UI/AdvancedWindow/ModEditWindow.Deformers.cs
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Text;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.UI.Classes;
|
||||
using Notification = OtterGui.Classes.Notification;
|
||||
|
||||
namespace Penumbra.UI.AdvancedWindow;
|
||||
|
||||
public partial class ModEditWindow
|
||||
{
|
||||
private readonly FileEditor<PbdTab> _pbdTab;
|
||||
private readonly PbdData _pbdData = new();
|
||||
|
||||
private bool DrawDeformerPanel(PbdTab tab, bool disabled)
|
||||
{
|
||||
_pbdData.Update(tab.File);
|
||||
DrawGenderRaceSelector(tab);
|
||||
ImGui.SameLine();
|
||||
DrawBoneSelector();
|
||||
ImGui.SameLine();
|
||||
return DrawBoneData(tab, disabled);
|
||||
}
|
||||
|
||||
private void DrawGenderRaceSelector(PbdTab tab)
|
||||
{
|
||||
using var group = ImUtf8.Group();
|
||||
var width = ImUtf8.CalcTextSize("Hellsguard - Female (Child)____0000"u8).X + 2 * ImGui.GetStyle().WindowPadding.X;
|
||||
using (ImRaii.PushStyle(ImGuiStyleVar.FrameRounding, 0)
|
||||
.Push(ImGuiStyleVar.ItemSpacing, Vector2.Zero))
|
||||
{
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImUtf8.InputText("##grFilter"u8, ref _pbdData.RaceCodeFilter, "Filter..."u8);
|
||||
}
|
||||
|
||||
using var child = ImUtf8.Child("GenderRace"u8, new Vector2(width, ImGui.GetContentRegionMax().Y), true);
|
||||
if (!child)
|
||||
return;
|
||||
|
||||
var metaColor = ColorId.ItemId.Value();
|
||||
foreach (var (deformer, index) in tab.File.Deformers.WithIndex())
|
||||
{
|
||||
var name = deformer.GenderRace.ToName();
|
||||
var raceCode = deformer.GenderRace.ToRaceCode();
|
||||
// No clipping necessary since this are not that many objects anyway.
|
||||
if (!name.Contains(_pbdData.RaceCodeFilter) && !raceCode.Contains(_pbdData.RaceCodeFilter))
|
||||
continue;
|
||||
|
||||
using var id = ImUtf8.PushId(index);
|
||||
using var color = ImRaii.PushColor(ImGuiCol.Text, ImGui.GetColorU32(ImGuiCol.TextDisabled), deformer.RacialDeformer.IsEmpty);
|
||||
if (ImUtf8.Selectable(name, deformer.GenderRace == _pbdData.SelectedRaceCode))
|
||||
{
|
||||
_pbdData.SelectedRaceCode = deformer.GenderRace;
|
||||
_pbdData.SelectedDeformer = deformer.RacialDeformer;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
color.Push(ImGuiCol.Text, metaColor);
|
||||
ImUtf8.TextRightAligned(raceCode);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawBoneSelector()
|
||||
{
|
||||
using var group = ImUtf8.Group();
|
||||
var width = 200 * ImUtf8.GlobalScale;
|
||||
using (ImRaii.PushStyle(ImGuiStyleVar.FrameRounding, 0)
|
||||
.Push(ImGuiStyleVar.ItemSpacing, Vector2.Zero))
|
||||
{
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImUtf8.InputText("##boneFilter"u8, ref _pbdData.BoneFilter, "Filter..."u8);
|
||||
}
|
||||
|
||||
using var child = ImUtf8.Child("Bone"u8, new Vector2(width, ImGui.GetContentRegionMax().Y), true);
|
||||
if (!child)
|
||||
return;
|
||||
|
||||
if (_pbdData.SelectedDeformer == null)
|
||||
return;
|
||||
|
||||
if (_pbdData.SelectedDeformer.IsEmpty)
|
||||
{
|
||||
ImUtf8.Text("<Empty>"u8);
|
||||
}
|
||||
else
|
||||
{
|
||||
var height = ImGui.GetTextLineHeightWithSpacing();
|
||||
var skips = ImGuiClip.GetNecessarySkips(height);
|
||||
var remainder = ImGuiClip.FilteredClippedDraw(_pbdData.SelectedDeformer.DeformMatrices.Keys, skips,
|
||||
b => b.Contains(_pbdData.BoneFilter), bone
|
||||
=>
|
||||
{
|
||||
if (ImUtf8.Selectable(bone, bone == _pbdData.SelectedBone))
|
||||
_pbdData.SelectedBone = bone;
|
||||
});
|
||||
ImGuiClip.DrawEndDummy(remainder, height);
|
||||
}
|
||||
}
|
||||
|
||||
private bool DrawBoneData(PbdTab tab, bool disabled)
|
||||
{
|
||||
using var child = ImUtf8.Child("Data"u8, ImGui.GetContentRegionMax() with { X = ImGui.GetContentRegionAvail().X}, true);
|
||||
if (!child)
|
||||
return false;
|
||||
|
||||
if (_pbdData.SelectedBone == null)
|
||||
return false;
|
||||
|
||||
if (!_pbdData.SelectedDeformer!.DeformMatrices.TryGetValue(_pbdData.SelectedBone, out var matrix))
|
||||
return false;
|
||||
|
||||
var width = UiBuilder.MonoFont.GetCharAdvance('0') * 12 + ImGui.GetStyle().FramePadding.X * 2;
|
||||
var dummyHeight = ImGui.GetTextLineHeight() / 2;
|
||||
var ret = DrawAddNewBone(tab, disabled, width);
|
||||
|
||||
ImUtf8.Dummy(0, dummyHeight);
|
||||
ImGui.Separator();
|
||||
ImUtf8.Dummy(0, dummyHeight);
|
||||
ret |= DrawDeformerMatrix(disabled, matrix, width);
|
||||
ImUtf8.Dummy(0, dummyHeight);
|
||||
ret |= DrawCopyPasteButtons(disabled, matrix, width);
|
||||
|
||||
|
||||
ImUtf8.Dummy(0, dummyHeight);
|
||||
ImGui.Separator();
|
||||
ImUtf8.Dummy(0, dummyHeight);
|
||||
ret |= DrawDecomposedData(disabled, matrix, width);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool DrawAddNewBone(PbdTab tab, bool disabled, float width)
|
||||
{
|
||||
var ret = false;
|
||||
ImUtf8.TextFrameAligned("Copy the values of the bone "u8);
|
||||
ImGui.SameLine(0, 0);
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, ColorId.NewMod.Value()))
|
||||
{
|
||||
ImUtf8.TextFrameAligned(_pbdData.SelectedBone);
|
||||
}
|
||||
ImGui.SameLine(0, 0);
|
||||
ImUtf8.TextFrameAligned(" to a new bone of name"u8);
|
||||
|
||||
var fullWidth = width * 4 + ImGui.GetStyle().ItemSpacing.X * 3;
|
||||
ImGui.SetNextItemWidth(fullWidth);
|
||||
ImUtf8.InputText("##newBone"u8, ref _pbdData.NewBoneName, "New Bone Name..."u8);
|
||||
ImUtf8.TextFrameAligned("for all races that have a corresponding bone."u8);
|
||||
ImGui.SameLine(0, fullWidth - width - ImGui.GetItemRectSize().X);
|
||||
if (!ImUtf8.ButtonEx("Apply"u8, ""u8, new Vector2(width, 0),
|
||||
disabled || _pbdData.NewBoneName.Length == 0 || _pbdData.SelectedBone == null))
|
||||
return ret;
|
||||
|
||||
foreach (var deformer in tab.File.Deformers)
|
||||
{
|
||||
if (!deformer.RacialDeformer.DeformMatrices.TryGetValue(_pbdData.SelectedBone!, out var existingMatrix))
|
||||
continue;
|
||||
|
||||
if (!deformer.RacialDeformer.DeformMatrices.TryAdd(_pbdData.NewBoneName, existingMatrix)
|
||||
&& deformer.RacialDeformer.DeformMatrices.TryGetValue(_pbdData.NewBoneName, out var newBoneMatrix)
|
||||
&& !newBoneMatrix.Equals(existingMatrix))
|
||||
Penumbra.Messager.AddMessage(new Notification(
|
||||
$"Could not add deformer matrix to {deformer.GenderRace.ToName()}, Bone {_pbdData.NewBoneName} because it already has a deformer that differs from the intended one.",
|
||||
NotificationType.Warning));
|
||||
else
|
||||
ret = true;
|
||||
}
|
||||
|
||||
_pbdData.NewBoneName = string.Empty;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool DrawDeformerMatrix(bool disabled, in TransformMatrix matrix, float width)
|
||||
{
|
||||
using var font = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
using var _ = ImRaii.Disabled(disabled);
|
||||
var ret = false;
|
||||
for (var i = 0; i < 3; ++i)
|
||||
{
|
||||
for (var j = 0; j < 4; ++j)
|
||||
{
|
||||
using var id = ImUtf8.PushId(i * 4 + j);
|
||||
ImGui.SetNextItemWidth(width);
|
||||
var tmp = matrix[i, j];
|
||||
if (ImUtf8.InputScalar(""u8, ref tmp, "% 12.8f"u8))
|
||||
{
|
||||
ret = true;
|
||||
_pbdData.SelectedDeformer!.DeformMatrices[_pbdData.SelectedBone!] = matrix.ChangeValue(i, j, tmp);
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
}
|
||||
|
||||
ImGui.NewLine();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool DrawCopyPasteButtons(bool disabled, in TransformMatrix matrix, float width)
|
||||
{
|
||||
var size = new Vector2(width, 0);
|
||||
if (ImUtf8.Button("Copy Values"u8, size))
|
||||
_pbdData.CopiedMatrix = matrix;
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImUtf8.ButtonEx("Paste Values"u8, ""u8, size, disabled || !_pbdData.CopiedMatrix.HasValue))
|
||||
{
|
||||
_pbdData.SelectedDeformer!.DeformMatrices[_pbdData.SelectedBone!] = _pbdData.CopiedMatrix!.Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool DrawDecomposedData(bool disabled, in TransformMatrix matrix, float width)
|
||||
{
|
||||
var ret = false;
|
||||
|
||||
|
||||
if (!matrix.TryDecompose(out var scale, out var rotation, out var translation))
|
||||
return false;
|
||||
|
||||
using (ImUtf8.Group())
|
||||
{
|
||||
using var font = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
using var _ = ImRaii.Disabled(disabled);
|
||||
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ret |= ImUtf8.InputScalar("##ScaleX"u8, ref scale.X, "% 12.8f"u8);
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ret |= ImUtf8.InputScalar("##ScaleY"u8, ref scale.Y, "% 12.8f"u8);
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ret |= ImUtf8.InputScalar("##ScaleZ"u8, ref scale.Z, "% 12.8f"u8);
|
||||
|
||||
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ret |= ImUtf8.InputScalar("##TranslationX"u8, ref translation.X, "% 12.8f"u8);
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ret |= ImUtf8.InputScalar("##TranslationY"u8, ref translation.Y, "% 12.8f"u8);
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ret |= ImUtf8.InputScalar("##TranslationZ"u8, ref translation.Z, "% 12.8f"u8);
|
||||
|
||||
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ret |= ImUtf8.InputScalar("##RotationR"u8, ref rotation.W, "% 12.8f"u8);
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ret |= ImUtf8.InputScalar("##RotationI"u8, ref rotation.X, "% 12.8f"u8);
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ret |= ImUtf8.InputScalar("##RotationJ"u8, ref rotation.Y, "% 12.8f"u8);
|
||||
ImGui.SameLine();
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ret |= ImUtf8.InputScalar("##RotationK"u8, ref rotation.Z, "% 12.8f"u8);
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
using (ImUtf8.Group())
|
||||
{
|
||||
ImUtf8.TextFrameAligned("Scale"u8);
|
||||
ImUtf8.TextFrameAligned("Translation"u8);
|
||||
ImUtf8.TextFrameAligned("Rotation (Quaternion, rijk)"u8);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
_pbdData.SelectedDeformer!.DeformMatrices[_pbdData.SelectedBone!] = TransformMatrix.Compose(scale, rotation, translation);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public class PbdTab(byte[] data, string filePath) : IWritable
|
||||
{
|
||||
public readonly string FilePath = filePath;
|
||||
|
||||
public readonly PbdFile File = new(data);
|
||||
|
||||
public bool Valid
|
||||
=> File.Valid;
|
||||
|
||||
public byte[] Write()
|
||||
=> File.Write();
|
||||
}
|
||||
|
||||
private class PbdData
|
||||
{
|
||||
public GenderRace SelectedRaceCode = GenderRace.Unknown;
|
||||
public RacialDeformer? SelectedDeformer;
|
||||
public string? SelectedBone;
|
||||
public string NewBoneName = string.Empty;
|
||||
public string BoneFilter = string.Empty;
|
||||
public string RaceCodeFilter = string.Empty;
|
||||
|
||||
public TransformMatrix? CopiedMatrix;
|
||||
|
||||
public void Update(PbdFile file)
|
||||
{
|
||||
if (SelectedRaceCode is GenderRace.Unknown)
|
||||
{
|
||||
SelectedDeformer = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedDeformer = file.Deformers.FirstOrDefault(p => p.GenderRace == SelectedRaceCode).RacialDeformer;
|
||||
if (SelectedDeformer is null)
|
||||
SelectedRaceCode = GenderRace.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -236,6 +236,8 @@ public partial class ModEditWindow : Window, IDisposable, IUiService
|
|||
_itemSwapTab.DrawContent();
|
||||
}
|
||||
|
||||
_pbdTab.Draw();
|
||||
|
||||
DrawMissingFilesTab();
|
||||
DrawMaterialReassignmentTab();
|
||||
}
|
||||
|
|
@ -665,6 +667,10 @@ public partial class ModEditWindow : Window, IDisposable, IUiService
|
|||
() => PopulateIsOnPlayer(_editor.Files.Shpk, ResourceType.Shpk), DrawShaderPackagePanel,
|
||||
() => Mod?.ModPath.FullName ?? string.Empty,
|
||||
(bytes, path, _) => new ShpkTab(_fileDialog, bytes, path));
|
||||
_pbdTab = new FileEditor<PbdTab>(this, _communicator, gameData, config, _editor.Compactor, _fileDialog, "Deformers", ".pbd",
|
||||
() => _editor.Files.Pbd, DrawDeformerPanel,
|
||||
() => Mod?.ModPath.FullName ?? string.Empty,
|
||||
(bytes, path, _) => new PbdTab(bytes, path));
|
||||
_center = new CombinedTexture(_left, _right);
|
||||
_textureSelectCombo = new TextureDrawer.PathSelectCombo(textures, editor, () => GetPlayerResourcesOfType(ResourceType.Tex));
|
||||
_resourceTreeFactory = resourceTreeFactory;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue