goatcorp / Dalamud

FFXIV plugin framework and API
GNU Affero General Public License v3.0
1.18k stars 272 forks source link

Changes for `ITextureProvider` #1629

Open Soreepeong opened 8 months ago

Soreepeong commented 8 months ago

A placeholder issue tracking changes for ITextureProvider.

Soreepeong commented 8 months ago

A suggestion for the interface:

public interface ITextureProvider
{
    /// <summary>Gets the corresponding game icon for use with the current frame.<br />
    /// Shortcut to calling <see cref="ImmediateGetFromGame"/> using <see cref="GameIconLookup.GetPath"/>.</summary>
    /// <param name="lookup">The icon specifier.</param>
    /// <returns>An instance of <see cref="IDalamudTextureWrap"/> that is guaranteed to be available for the current
    /// frame being drawn.</returns>
    /// <remarks><see cref="IDisposable.Dispose"/> will be ignored.<br />
    /// If the file is unavailable, then the returned instance of <see cref="IDalamudTextureWrap"/> will point to an
    /// empty texture instead.</remarks>
    /// <exception cref="InvalidOperationException">Thrown when called outside the UI thread.</exception>
    public IDalamudTextureWrap ImmediateGetFromGameIcon(GameIconLookup lookup);

    /// <summary>Gets a texture from a file shipped as a part of the game resources for use with the current frame.
    /// </summary>
    /// <param name="path">The game-internal path to a .tex, .atex, or an image file such as .png.</param>
    /// <returns>An instance of <see cref="IDalamudTextureWrap"/> that is guaranteed to be available for the current
    /// frame being drawn.</returns>
    /// <remarks><see cref="IDisposable.Dispose"/> will be ignored.<br />
    /// If the file is unavailable, then the returned instance of <see cref="IDalamudTextureWrap"/> will point to an
    /// empty texture instead.</remarks>
    /// <exception cref="InvalidOperationException">Thrown when called outside the UI thread.</exception>
    public IDalamudTextureWrap ImmediateGetFromGame(string path);

    /// <summary>Gets a texture from a file on the filesystem for use with the current frame.</summary>
    /// <param name="file">The filesystem path to a .tex, .atex, or an image file such as .png.</param>
    /// <returns>An instance of <see cref="IDalamudTextureWrap"/> that is guaranteed to be available for the current
    /// frame being drawn.</returns>
    /// <remarks><see cref="IDisposable.Dispose"/> will be ignored.<br />
    /// If the file is unavailable, then the returned instance of <see cref="IDalamudTextureWrap"/> will point to an
    /// empty texture instead.</remarks>
    /// <exception cref="InvalidOperationException">Thrown when called outside the UI thread.</exception>
    public IDalamudTextureWrap ImmediateGetFromFile(FileInfo file);

    /// <summary>Gets the corresponding game icon.<br />
    /// Shortcut to calling <see cref="GetFromGameAsync"/> using <see cref="GameIconLookup.GetPath"/>.</summary>
    /// <param name="lookup">The icon specifier.</param>
    /// <returns>A <see cref="Task{TResult}"/> containing the loaded texture on success. Dispose after use.</returns>
    public Task<IDalamudTextureWrap> GetFromGameIconAsync(GameIconLookup lookup);

    /// <summary>Gets a texture from a file shipped as a part of the game resources.</summary>
    /// <param name="path">The game-internal path to a .tex, .atex, or an image file such as .png.</param>
    /// <returns>A <see cref="Task{TResult}"/> containing the loaded texture on success. Dispose after use.</returns>
    public Task<IDalamudTextureWrap> GetFromGameAsync(string path);

    /// <summary>Gets a texture from a file on the filesystem.</summary>
    /// <param name="file">The filesystem path to a .tex, .atex, or an image file such as .png.</param>
    /// <returns>A <see cref="Task{TResult}"/> containing the loaded texture on success. Dispose after use.</returns>
    public Task<IDalamudTextureWrap> GetFromFileAsync(FileInfo file);

    /// <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>
    /// <returns>A <see cref="Task{TResult}"/> containing the loaded texture on success. Dispose after use.</returns>
    public Task<IDalamudTextureWrap> GetFromImageAsync(ReadOnlyMemory<byte> bytes);

    /// <summary>Gets a texture from the given stream, trying to interpret it as a .tex file or other well-known image
    /// files, such as .png.</summary>
    /// <param name="stream">The stream to load data from.</param>
    /// <param name="leaveOpen">Whether to leave the stream open once the task completes, sucessfully or not.</param>
    /// <returns>A <see cref="Task{TResult}"/> containing the loaded texture on success. Dispose after use.</returns>
    public Task<IDalamudTextureWrap> GetFromImageAsync(Stream stream, bool leaveOpen = false);

    /// <summary>Gets a texture from the given bytes, interpreting it as a raw bitmap.</summary>
    /// <param name="specs">The specifications for the raw bitmap.</param>
    /// <param name="bytes">The bytes to load.</param>
    /// <returns>The texture loaded from the supplied raw bitmap. Dispose after use.</returns>
    public IDalamudTextureWrap GetFromRaw(RawImageSpecs specs, ReadOnlySpan<byte> bytes);

    /// <summary>Gets a texture from the given bytes, interpreting it as a raw bitmap.</summary>
    /// <param name="specs">The specifications for the raw bitmap.</param>
    /// <param name="bytes">The bytes to load.</param>
    /// <returns>A <see cref="Task{TResult}"/> containing the loaded texture on success. Dispose after use.</returns>
    public Task<IDalamudTextureWrap> GetFromRawAsync(RawImageSpecs specs, ReadOnlyMemory<byte> bytes);

    /// <summary>Gets a texture from the given stream, interpreting the read data as a raw bitmap.</summary>
    /// <param name="specs">The specifications for the raw bitmap.</param>
    /// <param name="stream">The stream to load data from.</param>
    /// <param name="leaveOpen">Whether to leave the stream open once the task completes, sucessfully or not.</param>
    /// <returns>A <see cref="Task{TResult}"/> containing the loaded texture on success. Dispose after use.</returns>
    public Task<IDalamudTextureWrap> GetFromRawAsync(RawImageSpecs specs, Stream stream, bool leaveOpen = false);
}

public record GameIconLookup(uint IconId, bool ItemHq = false, bool HiRes = true, ClientLanguage? Language = null)
{
    public string GetPath(ClientLanguage defaultLanguage) => throw new NotImplementedException();
}

public record RawImageSpecs(int Width, int Height, int Pitch, DXGI_FORMAT Format)
{
    public static RawImageSpecs Bgra32(int width, int height) =>
        new(width, height, width * 4, DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM);

    public static RawImageSpecs Rgba32(int width, int height) =>
        new(width, height, width * 4, DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM);
}
Soreepeong commented 8 months ago

On Immediate... functions: what would be the most common use case? Should they return null or return an empty texture if the files are not (yet) available? If null is returned, then ITextureProvider.Immediate...(...) ?? IDalamudAssetManager.Empty4X4 can be used to obtain a fallback texture.