mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
Add ITextureProvider.GetFromManifestResource(Assembly,string)
This commit is contained in:
parent
b52d4724e9
commit
cc756c243c
5 changed files with 327 additions and 35 deletions
|
|
@ -0,0 +1,64 @@
|
|||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Dalamud.Utility;
|
||||
|
||||
namespace Dalamud.Interface.Internal.SharedImmediateTextures;
|
||||
|
||||
/// <summary>Represents a sharable texture, based on a manifest texture obtained from
|
||||
/// <see cref="Assembly.GetManifestResourceStream(string)"/>.</summary>
|
||||
internal sealed class ManifestResourceSharedImmediateTexture : SharedImmediateTexture
|
||||
{
|
||||
private readonly Assembly assembly;
|
||||
private readonly string name;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="ManifestResourceSharedImmediateTexture"/> class.</summary>
|
||||
/// <param name="assembly">The assembly containing manifest resources.</param>
|
||||
/// <param name="name">The case-sensitive name of the manifest resource being requested.</param>
|
||||
private ManifestResourceSharedImmediateTexture(Assembly assembly, string name)
|
||||
{
|
||||
this.assembly = assembly;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string SourcePathForDebug => $"{this.assembly.GetName().FullName}:{this.name}";
|
||||
|
||||
/// <summary>Creates a new placeholder instance of <see cref="ManifestResourceSharedImmediateTexture"/>.</summary>
|
||||
/// <param name="args">The arguments to pass to the constructor.</param>
|
||||
/// <returns>The new instance.</returns>
|
||||
public static SharedImmediateTexture CreatePlaceholder((Assembly Assembly, string Name) args) =>
|
||||
new ManifestResourceSharedImmediateTexture(args.Assembly, args.Name);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString() =>
|
||||
$"{nameof(ManifestResourceSharedImmediateTexture)}#{this.InstanceIdForDebug}({this.SourcePathForDebug})";
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void ReleaseResources()
|
||||
{
|
||||
_ = this.UnderlyingWrap?.ToContentDisposedTask(true);
|
||||
this.UnderlyingWrap = null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void ReviveResources() =>
|
||||
this.UnderlyingWrap = Service<TextureLoadThrottler>.Get().CreateLoader(
|
||||
this,
|
||||
this.CreateTextureAsync,
|
||||
this.LoadCancellationToken);
|
||||
|
||||
private async Task<IDalamudTextureWrap> CreateTextureAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await using var stream = this.assembly.GetManifestResourceStream(this.name);
|
||||
if (stream is null)
|
||||
throw new FileNotFoundException("The resource file could not be found.");
|
||||
|
||||
var tm = await Service<TextureManager>.GetAsync();
|
||||
var ms = new MemoryStream(stream.CanSeek ? (int)stream.Length : 0);
|
||||
await stream.CopyToAsync(ms, cancellationToken);
|
||||
return tm.NoThrottleGetFromImage(ms.GetBuffer().AsMemory(0, (int)ms.Length));
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ using System.Collections.Concurrent;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -17,6 +18,7 @@ using Dalamud.Logging.Internal;
|
|||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
|
||||
using Lumina.Data;
|
||||
using Lumina.Data.Files;
|
||||
|
||||
using SharpDX;
|
||||
|
|
@ -59,8 +61,14 @@ internal sealed class TextureManager : IServiceType, IDisposable, ITextureProvid
|
|||
private readonly TextureLoadThrottler textureLoadThrottler = Service<TextureLoadThrottler>.Get();
|
||||
|
||||
private readonly ConcurrentLru<GameIconLookup, string> lookupToPath = new(PathLookupLruCount);
|
||||
|
||||
private readonly ConcurrentDictionary<string, SharedImmediateTexture> gamePathTextures = new();
|
||||
|
||||
private readonly ConcurrentDictionary<string, SharedImmediateTexture> fileSystemTextures = new();
|
||||
|
||||
private readonly ConcurrentDictionary<(Assembly Assembly, string Name), SharedImmediateTexture>
|
||||
manifestResourceTextures = new();
|
||||
|
||||
private readonly HashSet<SharedImmediateTexture> invalidatedTextures = new();
|
||||
|
||||
private bool disposing;
|
||||
|
|
@ -71,12 +79,15 @@ internal sealed class TextureManager : IServiceType, IDisposable, ITextureProvid
|
|||
/// <inheritdoc/>
|
||||
public event ITextureSubstitutionProvider.TextureDataInterceptorDelegate? InterceptTexDataLoad;
|
||||
|
||||
/// <summary>Gets all the loaded textures from the game resources.</summary>
|
||||
/// <summary>Gets all the loaded textures from game resources.</summary>
|
||||
public ICollection<SharedImmediateTexture> GamePathTexturesForDebug => this.gamePathTextures.Values;
|
||||
|
||||
/// <summary>Gets all the loaded textures from the game resources.</summary>
|
||||
/// <summary>Gets all the loaded textures from filesystem.</summary>
|
||||
public ICollection<SharedImmediateTexture> FileSystemTexturesForDebug => this.fileSystemTextures.Values;
|
||||
|
||||
/// <summary>Gets all the loaded textures from assembly manifest resources.</summary>
|
||||
public ICollection<SharedImmediateTexture> ManifestResourceTexturesForDebug => this.manifestResourceTextures.Values;
|
||||
|
||||
/// <summary>Gets all the loaded textures that are invalidated from <see cref="InvalidatePaths"/>.</summary>
|
||||
/// <remarks><c>lock</c> on use of the value returned from this property.</remarks>
|
||||
[SuppressMessage(
|
||||
|
|
@ -92,14 +103,20 @@ internal sealed class TextureManager : IServiceType, IDisposable, ITextureProvid
|
|||
return;
|
||||
|
||||
this.disposing = true;
|
||||
foreach (var v in this.gamePathTextures.Values)
|
||||
v.ReleaseSelfReference(true);
|
||||
foreach (var v in this.fileSystemTextures.Values)
|
||||
v.ReleaseSelfReference(true);
|
||||
|
||||
ReleaseSelfReferences(this.gamePathTextures);
|
||||
ReleaseSelfReferences(this.fileSystemTextures);
|
||||
ReleaseSelfReferences(this.manifestResourceTextures);
|
||||
this.lookupToPath.Clear();
|
||||
this.gamePathTextures.Clear();
|
||||
this.fileSystemTextures.Clear();
|
||||
|
||||
return;
|
||||
|
||||
static void ReleaseSelfReferences<T>(ConcurrentDictionary<T, SharedImmediateTexture> dict)
|
||||
{
|
||||
foreach (var v in dict.Values)
|
||||
v.ReleaseSelfReference(true);
|
||||
dict.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
#region API9 compat
|
||||
|
|
@ -157,13 +174,29 @@ internal sealed class TextureManager : IServiceType, IDisposable, ITextureProvid
|
|||
|
||||
/// <inheritdoc cref="ITextureProvider.GetFromGame"/>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public SharedImmediateTexture GetFromGame(string path) =>
|
||||
this.gamePathTextures.GetOrAdd(path, GamePathSharedImmediateTexture.CreatePlaceholder);
|
||||
public SharedImmediateTexture GetFromGame(string path)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(this.disposing, this);
|
||||
return this.gamePathTextures.GetOrAdd(path, GamePathSharedImmediateTexture.CreatePlaceholder);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ITextureProvider.GetFromFile"/>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public SharedImmediateTexture GetFromFile(string path) =>
|
||||
this.fileSystemTextures.GetOrAdd(path, FileSystemSharedImmediateTexture.CreatePlaceholder);
|
||||
public SharedImmediateTexture GetFromFile(string path)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(this.disposing, this);
|
||||
return this.fileSystemTextures.GetOrAdd(path, FileSystemSharedImmediateTexture.CreatePlaceholder);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ITextureProvider.GetFromFile"/>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public SharedImmediateTexture GetFromManifestResource(Assembly assembly, string name)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(this.disposing, this);
|
||||
return this.manifestResourceTextures.GetOrAdd(
|
||||
(assembly, name),
|
||||
ManifestResourceSharedImmediateTexture.CreatePlaceholder);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
|
@ -177,6 +210,11 @@ internal sealed class TextureManager : IServiceType, IDisposable, ITextureProvid
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
ISharedImmediateTexture ITextureProvider.GetFromFile(string path) => this.GetFromFile(path);
|
||||
|
||||
/// <inheritdoc/>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
ISharedImmediateTexture ITextureProvider.GetFromManifestResource(Assembly assembly, string name) =>
|
||||
this.GetFromManifestResource(assembly, name);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IDalamudTextureWrap> CreateFromImageAsync(
|
||||
ReadOnlyMemory<byte> bytes,
|
||||
|
|
@ -433,15 +471,39 @@ internal sealed class TextureManager : IServiceType, IDisposable, ITextureProvid
|
|||
/// <returns>The loaded texture.</returns>
|
||||
internal IDalamudTextureWrap NoThrottleGetFromImage(ReadOnlyMemory<byte> bytes)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(this.disposing, this);
|
||||
|
||||
if (this.interfaceManager.Scene is not { } scene)
|
||||
{
|
||||
_ = Service<InterfaceManager.InterfaceManagerWithScene>.Get();
|
||||
scene = this.interfaceManager.Scene ?? throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
var bytesArray = bytes.ToArray();
|
||||
var texFileAttemptException = default(Exception);
|
||||
if (TexFileExtensions.IsPossiblyTexFile2D(bytesArray))
|
||||
{
|
||||
var tf = new TexFile();
|
||||
typeof(TexFile).GetProperty(nameof(tf.Data))!.GetSetMethod(true)!.Invoke(
|
||||
tf,
|
||||
new object?[] { bytesArray });
|
||||
typeof(TexFile).GetProperty(nameof(tf.Reader))!.GetSetMethod(true)!.Invoke(
|
||||
tf,
|
||||
new object?[] { new LuminaBinaryReader(bytesArray) });
|
||||
// Note: FileInfo and FilePath are not used from TexFile; skip it.
|
||||
try
|
||||
{
|
||||
return this.NoThrottleGetFromTexFile(tf);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
texFileAttemptException = e;
|
||||
}
|
||||
}
|
||||
|
||||
return new DalamudTextureWrap(
|
||||
scene.LoadImage(bytes.ToArray())
|
||||
?? throw new("Failed to load image because of an unknown reason."));
|
||||
scene.LoadImage(bytesArray)
|
||||
?? throw texFileAttemptException ?? new("Failed to load image because of an unknown reason."));
|
||||
}
|
||||
|
||||
/// <summary>Gets a texture from the given <see cref="TexFile"/>. Skips the load throttler; intended to be used from
|
||||
|
|
@ -450,6 +512,8 @@ internal sealed class TextureManager : IServiceType, IDisposable, ITextureProvid
|
|||
/// <returns>The loaded texture.</returns>
|
||||
internal IDalamudTextureWrap NoThrottleGetFromTexFile(TexFile file)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(this.disposing, this);
|
||||
|
||||
var buffer = file.TextureBuffer;
|
||||
var (dxgiFormat, conversion) = TexFile.GetDxgiFormatFromTextureFormat(file.Header.Format, false);
|
||||
if (conversion != TexFile.DxgiFormatConversion.NoConversion || !this.SupportsDxgiFormat(dxgiFormat))
|
||||
|
|
@ -476,23 +540,9 @@ internal sealed class TextureManager : IServiceType, IDisposable, ITextureProvid
|
|||
|
||||
private void FrameworkOnUpdate(IFramework unused)
|
||||
{
|
||||
if (!this.gamePathTextures.IsEmpty)
|
||||
{
|
||||
foreach (var (k, v) in this.gamePathTextures)
|
||||
{
|
||||
if (TextureFinalReleasePredicate(v))
|
||||
_ = this.gamePathTextures.TryRemove(k, out _);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.fileSystemTextures.IsEmpty)
|
||||
{
|
||||
foreach (var (k, v) in this.fileSystemTextures)
|
||||
{
|
||||
if (TextureFinalReleasePredicate(v))
|
||||
_ = this.fileSystemTextures.TryRemove(k, out _);
|
||||
}
|
||||
}
|
||||
RemoveFinalReleased(this.gamePathTextures);
|
||||
RemoveFinalReleased(this.fileSystemTextures);
|
||||
RemoveFinalReleased(this.manifestResourceTextures);
|
||||
|
||||
// ReSharper disable once InconsistentlySynchronizedField
|
||||
if (this.invalidatedTextures.Count != 0)
|
||||
|
|
@ -503,6 +553,20 @@ internal sealed class TextureManager : IServiceType, IDisposable, ITextureProvid
|
|||
|
||||
return;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
static void RemoveFinalReleased<T>(ConcurrentDictionary<T, SharedImmediateTexture> dict)
|
||||
{
|
||||
if (!dict.IsEmpty)
|
||||
{
|
||||
foreach (var (k, v) in dict)
|
||||
{
|
||||
if (TextureFinalReleasePredicate(v))
|
||||
_ = dict.TryRemove(k, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
static bool TextureFinalReleasePredicate(SharedImmediateTexture v) =>
|
||||
v.ContentQueried && v.ReleaseSelfReference(false) == 0 && !v.HasRevivalPossibility;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Dalamud.Interface.Components;
|
||||
|
|
@ -27,6 +30,11 @@ internal class TexWidget : IDataWindowWidget
|
|||
private bool hq = false;
|
||||
private string inputTexPath = string.Empty;
|
||||
private string inputFilePath = string.Empty;
|
||||
private Assembly[]? inputManifestResourceAssemblyCandidates;
|
||||
private string[]? inputManifestResourceAssemblyCandidateNames;
|
||||
private int inputManifestResourceAssemblyIndex;
|
||||
private string[]? inputManifestResourceNameCandidates;
|
||||
private int inputManifestResourceNameIndex;
|
||||
private Vector2 inputTexUv0 = Vector2.Zero;
|
||||
private Vector2 inputTexUv1 = Vector2.One;
|
||||
private Vector4 inputTintCol = Vector4.One;
|
||||
|
|
@ -53,6 +61,11 @@ internal class TexWidget : IDataWindowWidget
|
|||
this.inputFilePath = Path.Join(
|
||||
Service<Dalamud>.Get().StartInfo.AssetDirectory!,
|
||||
DalamudAsset.Logo.GetAttribute<DalamudAssetPathAttribute>()!.FileName);
|
||||
this.inputManifestResourceAssemblyCandidates = null;
|
||||
this.inputManifestResourceAssemblyCandidateNames = null;
|
||||
this.inputManifestResourceAssemblyIndex = 0;
|
||||
this.inputManifestResourceNameCandidates = null;
|
||||
this.inputManifestResourceNameIndex = 0;
|
||||
this.Ready = true;
|
||||
}
|
||||
|
||||
|
|
@ -65,19 +78,28 @@ internal class TexWidget : IDataWindowWidget
|
|||
GC.Collect();
|
||||
|
||||
ImGui.PushID("loadedGameTextures");
|
||||
if (ImGui.CollapsingHeader($"Loaded Game Textures: {this.textureManager.GamePathTexturesForDebug.Count:g}###header"))
|
||||
if (ImGui.CollapsingHeader(
|
||||
$"Loaded Game Textures: {this.textureManager.GamePathTexturesForDebug.Count:g}###header"))
|
||||
this.DrawLoadedTextures(this.textureManager.GamePathTexturesForDebug);
|
||||
ImGui.PopID();
|
||||
|
||||
ImGui.PushID("loadedFileTextures");
|
||||
if (ImGui.CollapsingHeader($"Loaded File Textures: {this.textureManager.FileSystemTexturesForDebug.Count:g}###header"))
|
||||
if (ImGui.CollapsingHeader(
|
||||
$"Loaded File Textures: {this.textureManager.FileSystemTexturesForDebug.Count:g}###header"))
|
||||
this.DrawLoadedTextures(this.textureManager.FileSystemTexturesForDebug);
|
||||
ImGui.PopID();
|
||||
|
||||
ImGui.PushID("loadedManifestResourceTextures");
|
||||
if (ImGui.CollapsingHeader(
|
||||
$"Loaded Manifest Resource Textures: {this.textureManager.ManifestResourceTexturesForDebug.Count:g}###header"))
|
||||
this.DrawLoadedTextures(this.textureManager.ManifestResourceTexturesForDebug);
|
||||
ImGui.PopID();
|
||||
|
||||
lock (this.textureManager.InvalidatedTexturesForDebug)
|
||||
{
|
||||
ImGui.PushID("invalidatedTextures");
|
||||
if (ImGui.CollapsingHeader($"Invalidated: {this.textureManager.InvalidatedTexturesForDebug.Count:g}###header"))
|
||||
if (ImGui.CollapsingHeader(
|
||||
$"Invalidated: {this.textureManager.InvalidatedTexturesForDebug.Count:g}###header"))
|
||||
{
|
||||
this.DrawLoadedTextures(this.textureManager.InvalidatedTexturesForDebug);
|
||||
}
|
||||
|
|
@ -86,16 +108,39 @@ internal class TexWidget : IDataWindowWidget
|
|||
}
|
||||
|
||||
if (ImGui.CollapsingHeader("Load Game File by Icon ID", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
ImGui.PushID(nameof(this.DrawIconInput));
|
||||
this.DrawIconInput();
|
||||
ImGui.PopID();
|
||||
}
|
||||
|
||||
if (ImGui.CollapsingHeader("Load Game File by Path", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
ImGui.PushID(nameof(this.DrawGamePathInput));
|
||||
this.DrawGamePathInput();
|
||||
ImGui.PopID();
|
||||
}
|
||||
|
||||
if (ImGui.CollapsingHeader("Load File", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
ImGui.PushID(nameof(this.DrawFileInput));
|
||||
this.DrawFileInput();
|
||||
ImGui.PopID();
|
||||
}
|
||||
|
||||
if (ImGui.CollapsingHeader("Load Assembly Manifest Resource", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
ImGui.PushID(nameof(this.DrawAssemblyManifestResourceInput));
|
||||
this.DrawAssemblyManifestResourceInput();
|
||||
ImGui.PopID();
|
||||
}
|
||||
|
||||
if (ImGui.CollapsingHeader("UV"))
|
||||
{
|
||||
ImGui.PushID(nameof(this.DrawUvInput));
|
||||
this.DrawUvInput();
|
||||
ImGui.PopID();
|
||||
}
|
||||
|
||||
TextureEntry? toRemove = null;
|
||||
TextureEntry? toCopy = null;
|
||||
|
|
@ -337,6 +382,81 @@ internal class TexWidget : IDataWindowWidget
|
|||
ImGuiHelpers.ScaledDummy(10);
|
||||
}
|
||||
|
||||
private void DrawAssemblyManifestResourceInput()
|
||||
{
|
||||
if (this.inputManifestResourceAssemblyCandidateNames is null ||
|
||||
this.inputManifestResourceAssemblyCandidates is null)
|
||||
{
|
||||
this.inputManifestResourceAssemblyIndex = 0;
|
||||
this.inputManifestResourceAssemblyCandidates =
|
||||
AssemblyLoadContext
|
||||
.All
|
||||
.SelectMany(x => x.Assemblies)
|
||||
.Distinct()
|
||||
.OrderBy(x => x.GetName().FullName)
|
||||
.ToArray();
|
||||
this.inputManifestResourceAssemblyCandidateNames =
|
||||
this.inputManifestResourceAssemblyCandidates
|
||||
.Select(x => x.GetName().FullName)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
if (ImGui.Combo(
|
||||
"Assembly",
|
||||
ref this.inputManifestResourceAssemblyIndex,
|
||||
this.inputManifestResourceAssemblyCandidateNames,
|
||||
this.inputManifestResourceAssemblyCandidateNames.Length))
|
||||
{
|
||||
this.inputManifestResourceNameIndex = 0;
|
||||
this.inputManifestResourceNameCandidates = null;
|
||||
}
|
||||
|
||||
var assembly =
|
||||
this.inputManifestResourceAssemblyIndex >= 0
|
||||
&& this.inputManifestResourceAssemblyIndex < this.inputManifestResourceAssemblyCandidates.Length
|
||||
? this.inputManifestResourceAssemblyCandidates[this.inputManifestResourceAssemblyIndex]
|
||||
: null;
|
||||
|
||||
this.inputManifestResourceNameCandidates ??= assembly?.GetManifestResourceNames() ?? Array.Empty<string>();
|
||||
|
||||
ImGui.Combo(
|
||||
"Name",
|
||||
ref this.inputManifestResourceNameIndex,
|
||||
this.inputManifestResourceNameCandidates,
|
||||
this.inputManifestResourceNameCandidates.Length);
|
||||
|
||||
var name =
|
||||
this.inputManifestResourceNameIndex >= 0
|
||||
&& this.inputManifestResourceNameIndex < this.inputManifestResourceNameCandidates.Length
|
||||
? this.inputManifestResourceNameCandidates[this.inputManifestResourceNameIndex]
|
||||
: null;
|
||||
|
||||
if (ImGui.Button("Refresh Assemblies"))
|
||||
{
|
||||
this.inputManifestResourceAssemblyIndex = 0;
|
||||
this.inputManifestResourceAssemblyCandidates = null;
|
||||
this.inputManifestResourceAssemblyCandidateNames = null;
|
||||
this.inputManifestResourceNameIndex = 0;
|
||||
this.inputManifestResourceNameCandidates = null;
|
||||
}
|
||||
|
||||
if (assembly is not null && name is not null)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Button("Load File (Async)"))
|
||||
{
|
||||
this.addedTextures.Add(
|
||||
new(Api10: this.textureManager.GetFromManifestResource(assembly, name).RentAsync()));
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Button("Load File (Immediate)"))
|
||||
this.addedTextures.Add(new(Api10ImmManifestResource: (assembly, name)));
|
||||
}
|
||||
|
||||
ImGuiHelpers.ScaledDummy(10);
|
||||
}
|
||||
|
||||
private void DrawUvInput()
|
||||
{
|
||||
ImGui.InputFloat2("UV0", ref this.inputTexUv0);
|
||||
|
|
@ -389,7 +509,8 @@ internal class TexWidget : IDataWindowWidget
|
|||
Task<IDalamudTextureWrap>? Api10 = null,
|
||||
GameIconLookup? Api10ImmGameIcon = null,
|
||||
string? Api10ImmGamePath = null,
|
||||
string? Api10ImmFile = null) : IDisposable
|
||||
string? Api10ImmFile = null,
|
||||
(Assembly Assembly, string Name)? Api10ImmManifestResource = null) : IDisposable
|
||||
{
|
||||
private static int idCounter;
|
||||
|
||||
|
|
@ -421,6 +542,8 @@ internal class TexWidget : IDataWindowWidget
|
|||
return "Must not happen";
|
||||
if (this.Api10ImmFile is not null)
|
||||
return "Must not happen";
|
||||
if (this.Api10ImmManifestResource is not null)
|
||||
return "Must not happen";
|
||||
return "Not implemented";
|
||||
}
|
||||
|
||||
|
|
@ -438,6 +561,13 @@ internal class TexWidget : IDataWindowWidget
|
|||
return tp.GetFromGame(this.Api10ImmGamePath).GetWrap();
|
||||
if (this.Api10ImmFile is not null)
|
||||
return tp.GetFromFile(this.Api10ImmFile).GetWrap();
|
||||
if (this.Api10ImmManifestResource is not null)
|
||||
{
|
||||
return tp.GetFromManifestResource(
|
||||
this.Api10ImmManifestResource.Value.Assembly,
|
||||
this.Api10ImmManifestResource.Value.Name).GetWrap();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -460,6 +590,8 @@ internal class TexWidget : IDataWindowWidget
|
|||
return $"{nameof(this.Api10ImmGamePath)}: {this.Api10ImmGamePath}";
|
||||
if (this.Api10ImmFile is not null)
|
||||
return $"{nameof(this.Api10ImmFile)}: {this.Api10ImmFile}";
|
||||
if (this.Api10ImmManifestResource is not null)
|
||||
return $"{nameof(this.Api10ImmManifestResource)}: {this.Api10ImmManifestResource}";
|
||||
return "Not implemented";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
@ -41,6 +42,12 @@ public partial interface ITextureProvider
|
|||
/// <returns>The shared texture that you may use to obtain the loaded texture wrap and load states.</returns>
|
||||
ISharedImmediateTexture GetFromFile(string path);
|
||||
|
||||
/// <summary>Gets a shared texture corresponding to the given file of the assembly manifest resources.</summary>
|
||||
/// <param name="assembly">The assembly containing manifest resources.</param>
|
||||
/// <param name="name">The case-sensitive name of the manifest resource being requested.</param>
|
||||
/// <returns>The shared texture that you may use to obtain the loaded texture wrap and load states.</returns>
|
||||
ISharedImmediateTexture GetFromManifestResource(Assembly assembly, string name);
|
||||
|
||||
/// <summary>Gets a texture from the given bytes, trying to interpret it as a .tex file or other well-known image
|
||||
/// files, such as .png.</summary>
|
||||
/// <param name="bytes">The bytes to load.</param>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
|
||||
using Dalamud.Memory;
|
||||
|
||||
using ImGuiScene;
|
||||
using Lumina.Data.Files;
|
||||
|
||||
|
|
@ -28,4 +32,25 @@ public static class TexFileExtensions
|
|||
|
||||
return dst;
|
||||
}
|
||||
|
||||
/// <summary>Determines if the given data is possibly a <see cref="TexFile"/>.</summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <returns><c>true</c> if it should be attempted to be interpreted as a <see cref="TexFile"/>.</returns>
|
||||
internal static unsafe bool IsPossiblyTexFile2D(ReadOnlySpan<byte> data)
|
||||
{
|
||||
if (data.Length < Unsafe.SizeOf<TexFile.TexHeader>())
|
||||
return false;
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
ref readonly var texHeader = ref MemoryHelper.Cast<TexFile.TexHeader>((nint)ptr);
|
||||
if ((texHeader.Type & TexFile.Attribute.TextureTypeMask) != TexFile.Attribute.TextureType2D)
|
||||
return false;
|
||||
if (!Enum.IsDefined(texHeader.Format))
|
||||
return false;
|
||||
if (texHeader.Width == 0 || texHeader.Height == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue