mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-16 05:34:25 +01:00
Improve file reading
This commit is contained in:
parent
db2081f14d
commit
e8fd452b8f
3 changed files with 34 additions and 46 deletions
|
|
@ -13,22 +13,16 @@ using ImageSharpConfiguration = SixLabors.ImageSharp.Configuration;
|
||||||
|
|
||||||
public class MaterialExporter
|
public class MaterialExporter
|
||||||
{
|
{
|
||||||
// input stuff
|
|
||||||
public struct Material
|
public struct Material
|
||||||
{
|
{
|
||||||
public MtrlFile Mtrl;
|
public MtrlFile Mtrl;
|
||||||
public Sampler[] Samplers;
|
public Dictionary<TextureUsage, Image<Rgba32>> Textures;
|
||||||
// variant?
|
// variant?
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct Sampler
|
|
||||||
{
|
|
||||||
public TextureUsage Usage;
|
|
||||||
public Image<Rgba32> Texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MaterialBuilder Export(Material material, string name)
|
public static MaterialBuilder Export(Material material, string name)
|
||||||
{
|
{
|
||||||
|
Penumbra.Log.Debug($"Exporting material \"{name}\".");
|
||||||
return material.Mtrl.ShaderPackage.Name switch
|
return material.Mtrl.ShaderPackage.Name switch
|
||||||
{
|
{
|
||||||
"character.shpk" => BuildCharacter(material, name),
|
"character.shpk" => BuildCharacter(material, name),
|
||||||
|
|
@ -40,11 +34,10 @@ public class MaterialExporter
|
||||||
{
|
{
|
||||||
// TODO: handle models with an underlying diffuse
|
// TODO: handle models with an underlying diffuse
|
||||||
var table = material.Mtrl.Table;
|
var table = material.Mtrl.Table;
|
||||||
// TODO: this should probably be a dict
|
|
||||||
var normal = material.Samplers
|
// TODO: there's a few normal usages i should check, i think.
|
||||||
.Where(s => s.Usage == TextureUsage.SamplerNormal)
|
// TODO: tryget
|
||||||
.First()
|
var normal = material.Textures[TextureUsage.SamplerNormal];
|
||||||
.Texture;
|
|
||||||
|
|
||||||
var operation = new ProcessCharacterNormalOperation(normal, table);
|
var operation = new ProcessCharacterNormalOperation(normal, table);
|
||||||
ParallelRowIterator.IterateRows(ImageSharpConfiguration.Default, normal.Bounds(), in operation);
|
ParallelRowIterator.IterateRows(ImageSharpConfiguration.Default, normal.Bounds(), in operation);
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,8 @@ public sealed class ModelManager(IFramework framework, ActiveCollections collect
|
||||||
_tasks.Clear();
|
_tasks.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task ExportToGltf(MdlFile mdl, IEnumerable<SklbFile> sklbs, string outputPath)
|
public Task ExportToGltf(MdlFile mdl, IEnumerable<string> sklbPaths, Func<string, byte[]> read, string outputPath)
|
||||||
=> Enqueue(new ExportToGltfAction(this, mdl, sklbs, outputPath));
|
=> Enqueue(new ExportToGltfAction(this, mdl, sklbPaths, read, outputPath));
|
||||||
|
|
||||||
public Task<MdlFile?> ImportGltf(string inputPath)
|
public Task<MdlFile?> ImportGltf(string inputPath)
|
||||||
{
|
{
|
||||||
|
|
@ -134,7 +134,7 @@ public sealed class ModelManager(IFramework framework, ActiveCollections collect
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ExportToGltfAction(ModelManager manager, MdlFile mdl, IEnumerable<SklbFile> sklbs, string outputPath)
|
private class ExportToGltfAction(ModelManager manager, MdlFile mdl, IEnumerable<string> sklbPaths, Func<string, byte[]> read, string outputPath)
|
||||||
: IAction
|
: IAction
|
||||||
{
|
{
|
||||||
public void Execute(CancellationToken cancel)
|
public void Execute(CancellationToken cancel)
|
||||||
|
|
@ -166,7 +166,8 @@ public sealed class ModelManager(IFramework framework, ActiveCollections collect
|
||||||
/// <summary> Attempt to read out the pertinent information from a .sklb. </summary>
|
/// <summary> Attempt to read out the pertinent information from a .sklb. </summary>
|
||||||
private IEnumerable<XivSkeleton> BuildSkeletons(CancellationToken cancel)
|
private IEnumerable<XivSkeleton> BuildSkeletons(CancellationToken cancel)
|
||||||
{
|
{
|
||||||
var havokTasks = sklbs
|
var havokTasks = sklbPaths
|
||||||
|
.Select(path => new SklbFile(read(path)))
|
||||||
.WithIndex()
|
.WithIndex()
|
||||||
.Select(CreateHavokTask)
|
.Select(CreateHavokTask)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
@ -197,29 +198,22 @@ public sealed class ModelManager(IFramework framework, ActiveCollections collect
|
||||||
if (absolutePath == null)
|
if (absolutePath == null)
|
||||||
throw new Exception("Failed to resolve material path.");
|
throw new Exception("Failed to resolve material path.");
|
||||||
|
|
||||||
// TODO: collection lookup and such. this is currently in mdltab (readsklb), and should be wholesale moved in here.
|
var mtrl = new MtrlFile(read(absolutePath));
|
||||||
var data = manager._gameData.GetFile(absolutePath);
|
|
||||||
if (data == null)
|
|
||||||
throw new Exception("Failed to fetch material game data.");
|
|
||||||
|
|
||||||
var mtrl = new MtrlFile(data.Data);
|
|
||||||
|
|
||||||
return new MaterialExporter.Material
|
return new MaterialExporter.Material
|
||||||
{
|
{
|
||||||
Mtrl = mtrl,
|
Mtrl = mtrl,
|
||||||
Samplers = mtrl.ShaderPackage.Samplers
|
Textures = mtrl.ShaderPackage.Samplers.ToDictionary(
|
||||||
.Select(sampler => new MaterialExporter.Sampler
|
sampler => (TextureUsage)sampler.SamplerId,
|
||||||
{
|
sampler => ConvertImage(mtrl.Textures[sampler.TextureIndex], cancel)
|
||||||
Usage = (TextureUsage)sampler.SamplerId,
|
),
|
||||||
Texture = ConvertImage(mtrl.Textures[sampler.TextureIndex], cancel),
|
|
||||||
})
|
|
||||||
.ToArray(),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private Image<Rgba32> ConvertImage(MtrlFile.Texture texture, CancellationToken cancel)
|
private Image<Rgba32> ConvertImage(MtrlFile.Texture texture, CancellationToken cancel)
|
||||||
{
|
{
|
||||||
var (image, _) = manager._textureManager.Load(texture.Path);
|
using var textureData = new MemoryStream(read(texture.Path));
|
||||||
|
var image = TexFileParser.Parse(textureData);
|
||||||
var pngImage = TextureManager.ConvertToPng(image, cancel).AsPng;
|
var pngImage = TextureManager.ConvertToPng(image, cancel).AsPng;
|
||||||
if (pngImage == null)
|
if (pngImage == null)
|
||||||
throw new Exception("Failed to convert texture to png.");
|
throw new Exception("Failed to convert texture to png.");
|
||||||
|
|
|
||||||
|
|
@ -116,11 +116,10 @@ public partial class ModEditWindow
|
||||||
/// <param name="mdlPath"> .mdl game path to resolve satellite files such as skeletons relative to. </param>
|
/// <param name="mdlPath"> .mdl game path to resolve satellite files such as skeletons relative to. </param>
|
||||||
public void Export(string outputPath, Utf8GamePath mdlPath)
|
public void Export(string outputPath, Utf8GamePath mdlPath)
|
||||||
{
|
{
|
||||||
IEnumerable<SklbFile> skeletons;
|
IEnumerable<string> sklbPaths;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var sklbPaths = _edit._models.ResolveSklbsForMdl(mdlPath.ToString(), GetCurrentEstManipulations());
|
sklbPaths = _edit._models.ResolveSklbsForMdl(mdlPath.ToString(), GetCurrentEstManipulations());
|
||||||
skeletons = sklbPaths.Select(ReadSklb).ToArray();
|
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
|
|
@ -129,7 +128,7 @@ public partial class ModEditWindow
|
||||||
}
|
}
|
||||||
|
|
||||||
PendingIo = true;
|
PendingIo = true;
|
||||||
_edit._models.ExportToGltf(Mdl, skeletons, outputPath)
|
_edit._models.ExportToGltf(Mdl, sklbPaths, ReadFile, outputPath)
|
||||||
.ContinueWith(task =>
|
.ContinueWith(task =>
|
||||||
{
|
{
|
||||||
RecordIoExceptions(task.Exception);
|
RecordIoExceptions(task.Exception);
|
||||||
|
|
@ -220,21 +219,23 @@ public partial class ModEditWindow
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Read a .sklb from the active collection or game. </summary>
|
/// <summary> Read a file from the active collection or game. </summary>
|
||||||
/// <param name="sklbPath"> Game path to the .sklb to load. </param>
|
/// <param name="path"> Game path to the file to load. </param>
|
||||||
private SklbFile ReadSklb(string sklbPath)
|
// TODO: Also look up files within the current mod regardless of mod state?
|
||||||
|
private byte[] ReadFile(string path)
|
||||||
{
|
{
|
||||||
// TODO: if cross-collection lookups are turned off, this conversion can be skipped
|
// TODO: if cross-collection lookups are turned off, this conversion can be skipped
|
||||||
if (!Utf8GamePath.FromString(sklbPath, out var utf8SklbPath, true))
|
if (!Utf8GamePath.FromString(path, out var utf8SklbPath, true))
|
||||||
throw new Exception($"Resolved skeleton path {sklbPath} could not be converted to a game path.");
|
throw new Exception($"Resolved path {path} could not be converted to a game path.");
|
||||||
|
|
||||||
var resolvedPath = _edit._activeCollections.Current.ResolvePath(utf8SklbPath);
|
var resolvedPath = _edit._activeCollections.Current.ResolvePath(utf8SklbPath);
|
||||||
// TODO: is it worth trying to use streams for these instead? I'll need to do this for mtrl/tex too, so might be a good idea. that said, the mtrl reader doesn't accept streams, so...
|
// TODO: is it worth trying to use streams for these instead? I'll need to do this for mtrl/tex too, so might be a good idea. that said, the mtrl reader doesn't accept streams, so...
|
||||||
var bytes = resolvedPath == null ? _edit._gameData.GetFile(sklbPath)?.Data : File.ReadAllBytes(resolvedPath.Value.ToPath());
|
var bytes = resolvedPath == null
|
||||||
return bytes != null
|
? _edit._gameData.GetFile(path)?.Data
|
||||||
? new SklbFile(bytes)
|
: File.ReadAllBytes(resolvedPath.Value.ToPath());
|
||||||
: throw new Exception(
|
|
||||||
$"Resolved skeleton path {sklbPath} could not be found. If modded, is it enabled in the current collection?");
|
return bytes ?? throw new Exception(
|
||||||
|
$"Resolved path {path} could not be found. If modded, is it enabled in the current collection?");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Remove the material given by the index. </summary>
|
/// <summary> Remove the material given by the index. </summary>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue