Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes for ITextureProvider #1629

Open
Soreepeong opened this issue Feb 5, 2024 · 2 comments
Open

Changes for ITextureProvider #1629

Soreepeong opened this issue Feb 5, 2024 · 2 comments

Comments

@Soreepeong
Copy link
Contributor

A placeholder issue tracking changes for ITextureProvider.

  • UiBuilder should lose texture-loading functions.
  • ITextureProvider should be clear with the lifecycle of loaded textures.
  • ...and more?
@Soreepeong
Copy link
Contributor Author

Soreepeong commented Feb 5, 2024

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);
}
  • Loading textures in general take enough time to be run off the main thread.
  • The internal data behind textures loaded from game resources and filesystem will be shared across plugins.

@Soreepeong
Copy link
Contributor Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant