mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-15 13:14:17 +01:00
119 lines
4.6 KiB
C#
119 lines
4.6 KiB
C#
using OtterGui;
|
|
using Penumbra.GameData;
|
|
using Penumbra.GameData.Files;
|
|
using Penumbra.Mods;
|
|
using Penumbra.String.Classes;
|
|
|
|
namespace Penumbra.UI.AdvancedWindow;
|
|
|
|
public partial class ModEditWindow
|
|
{
|
|
private class MdlTab : IWritable
|
|
{
|
|
public readonly MdlFile Mdl;
|
|
public readonly List<Utf8GamePath> GamePaths;
|
|
|
|
private readonly List<string>[] _attributes;
|
|
|
|
public MdlTab(byte[] bytes, string path, Mod? mod)
|
|
{
|
|
Mdl = new MdlFile(bytes);
|
|
GamePaths = mod == null ? new() : FindGamePaths(path, mod);
|
|
_attributes = CreateAttributes(Mdl);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Valid
|
|
=> Mdl.Valid;
|
|
|
|
/// <inheritdoc/>
|
|
public byte[] Write()
|
|
=> Mdl.Write();
|
|
|
|
// TODO: this _needs_ to be done asynchronously, kart mods hang for a good second or so
|
|
private List<Utf8GamePath> FindGamePaths(string path, Mod mod)
|
|
{
|
|
// todo: might be worth ordering based on prio + selection for disambiguating between multiple matches? not sure. same for the multi group case
|
|
return mod.AllSubMods
|
|
.SelectMany(submod => submod.Files.Concat(submod.FileSwaps))
|
|
// todo: using ordinal ignore case because the option group paths in mods being lowerecased somewhere, but the mod editor using fs paths, which may be uppercase. i'd say this will blow up on linux, but it's already the case so can't be too much worse than present right
|
|
.Where(kv => kv.Value.FullName.Equals(path, StringComparison.OrdinalIgnoreCase))
|
|
.Select(kv => kv.Key)
|
|
.ToList();
|
|
}
|
|
|
|
/// <summary> Remove the material given by the index. </summary>
|
|
/// <remarks> Meshes using the removed material are redirected to material 0, and those after the index are corrected. </remarks>
|
|
public void RemoveMaterial(int materialIndex)
|
|
{
|
|
for (var meshIndex = 0; meshIndex < Mdl.Meshes.Length; meshIndex++)
|
|
{
|
|
var newIndex = Mdl.Meshes[meshIndex].MaterialIndex;
|
|
if (newIndex == materialIndex)
|
|
newIndex = 0;
|
|
else if (newIndex > materialIndex)
|
|
--newIndex;
|
|
|
|
Mdl.Meshes[meshIndex].MaterialIndex = newIndex;
|
|
}
|
|
|
|
Mdl.Materials = Mdl.Materials.RemoveItems(materialIndex);
|
|
}
|
|
|
|
/// <summary> Create a list of attributes per sub mesh. </summary>
|
|
private static List<string>[] CreateAttributes(MdlFile mdl)
|
|
=> mdl.SubMeshes.Select(s => Enumerable.Range(0, 32)
|
|
.Where(idx => ((s.AttributeIndexMask >> idx) & 1) == 1)
|
|
.Select(idx => mdl.Attributes[idx])
|
|
.ToList()
|
|
).ToArray();
|
|
|
|
/// <summary> Obtain the attributes associated with a sub mesh by its index. </summary>
|
|
public IReadOnlyList<string> GetSubMeshAttributes(int subMeshIndex)
|
|
=> _attributes[subMeshIndex];
|
|
|
|
/// <summary> Remove or add attributes from a sub mesh by its index. </summary>
|
|
/// <param name="subMeshIndex"> The index of the sub mesh to update. </param>
|
|
/// <param name="old"> If non-null, remove this attribute. </param>
|
|
/// <param name="new"> If non-null, add this attribute. </param>
|
|
public void UpdateSubMeshAttribute(int subMeshIndex, string? old, string? @new)
|
|
{
|
|
var attributes = _attributes[subMeshIndex];
|
|
|
|
if (old != null)
|
|
attributes.Remove(old);
|
|
|
|
if (@new != null)
|
|
attributes.Add(@new);
|
|
|
|
PersistAttributes();
|
|
}
|
|
|
|
/// <summary> Apply changes to attributes to the file in memory. </summary>
|
|
private void PersistAttributes()
|
|
{
|
|
var allAttributes = new List<string>();
|
|
|
|
foreach (var (attributes, subMeshIndex) in _attributes.WithIndex())
|
|
{
|
|
var mask = 0u;
|
|
|
|
foreach (var attribute in attributes)
|
|
{
|
|
var attributeIndex = allAttributes.IndexOf(attribute);
|
|
if (attributeIndex == -1)
|
|
{
|
|
allAttributes.Add(attribute);
|
|
attributeIndex = allAttributes.Count - 1;
|
|
}
|
|
|
|
mask |= 1u << attributeIndex;
|
|
}
|
|
|
|
Mdl.SubMeshes[subMeshIndex].AttributeIndexMask = mask;
|
|
}
|
|
|
|
Mdl.Attributes = [.. allAttributes];
|
|
}
|
|
}
|
|
}
|