Skip to content

Commit

Permalink
Fix image loading
Browse files Browse the repository at this point in the history
  • Loading branch information
WorkingRobot committed Jul 1, 2024
1 parent 736a9a7 commit 716fa55
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 90 deletions.
12 changes: 6 additions & 6 deletions Craftimizer/Plugin.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
using Craftimizer.Plugin.Utils;
using Craftimizer.Plugin.Windows;
using Craftimizer.Simulator;
using Craftimizer.Simulator.Actions;
using Craftimizer.Utils;
using Craftimizer.Windows;
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.Textures;
using Dalamud.Interface.Textures.TextureWraps;
using Dalamud.Interface.Windowing;
using Dalamud.Plugin;
using System;
Expand All @@ -20,7 +17,7 @@ public sealed class Plugin : IDalamudPlugin
public string Version { get; }
public string Author { get; }
public string BuildConfiguration { get; }
public ISharedImmediateTexture Icon { get; }
public ILoadedTextureIcon Icon { get; }

public WindowSystem WindowSystem { get; }
public Settings SettingsWindow { get; }
Expand All @@ -31,6 +28,7 @@ public sealed class Plugin : IDalamudPlugin
public MacroClipboard? ClipboardWindow { get; private set; }

public Configuration Configuration { get; }
public IconManager IconManager { get; }
public Hooks Hooks { get; }
public Chat Chat { get; }
public CommunityMacros CommunityMacros { get; }
Expand All @@ -42,6 +40,7 @@ public Plugin(IDalamudPluginInterface pluginInterface)

WindowSystem = new("Craftimizer");
Configuration = Configuration.Load();
IconManager = new();
Hooks = new();
Chat = new();
CommunityMacros = new();
Expand All @@ -51,8 +50,7 @@ public Plugin(IDalamudPluginInterface pluginInterface)
Version = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()!.InformationalVersion.Split('+')[0];
Author = assembly.GetCustomAttribute<AssemblyCompanyAttribute>()!.Company;
BuildConfiguration = assembly.GetCustomAttribute<AssemblyConfigurationAttribute>()!.Configuration;
var now = DateTime.Now;
if (now.Day == 1 && now.Month == 4)
if (DateTime.Now is { Day: 1, Month: 4 })
Icon = IconManager.GetAssemblyTexture("horse_icon.png");
else
Icon = IconManager.GetAssemblyTexture("icon.png");
Expand Down Expand Up @@ -167,6 +165,8 @@ public void Dispose()
ListWindow.Dispose();
EditorWindow?.Dispose();
ClipboardWindow?.Dispose();
IconManager.Dispose();
Hooks.Dispose();
Icon.Dispose();
}
}
1 change: 1 addition & 0 deletions Craftimizer/Service.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public sealed class Service

public static Plugin Plugin { get; private set; }
public static Configuration Configuration => Plugin.Configuration;
public static IconManager IconManager => Plugin.IconManager;
public static WindowSystem WindowSystem => Plugin.WindowSystem;
public static Chat Chat => Plugin.Chat;
public static CommunityMacros CommunityMacros => Plugin.CommunityMacros;
Expand Down
12 changes: 6 additions & 6 deletions Craftimizer/SimulatorUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,15 @@ public static string GetName(this ActionType me, ClassJob classJob)
return "Unknown";
}

public static ISharedImmediateTexture GetIcon(this ActionType me, ClassJob classJob)
public static ITextureIcon GetIcon(this ActionType me, ClassJob classJob)
{
var (craftAction, action) = GetActionRow(me, classJob);
if (craftAction != null)
return IconManager.GetIcon(craftAction.Icon);
return Service.IconManager.GetIconCached(craftAction.Icon);
if (action != null)
return IconManager.GetIcon(action.Icon);
return Service.IconManager.GetIconCached(action.Icon);
// Old "Steady Hand" action icon
return IconManager.GetIcon(1953);
return Service.IconManager.GetIconCached(1953);
}

public static ActionType? GetActionTypeFromId(uint actionId, ClassJob classJob, bool isCraftAction)
Expand Down Expand Up @@ -331,8 +331,8 @@ public static ushort GetIconId(this EffectType me, int strength)
return (ushort)iconId;
}

public static ISharedImmediateTexture GetIcon(this EffectType me, int strength) =>
IconManager.GetIcon(me.GetIconId(strength));
public static ITextureIcon GetIcon(this EffectType me, int strength) =>
Service.IconManager.GetIconCached(me.GetIconId(strength));

public static string GetTooltip(this EffectType me, int strength, int duration)
{
Expand Down
115 changes: 106 additions & 9 deletions Craftimizer/Utils/IconManager.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,124 @@
using Craftimizer.Plugin;
using Dalamud.Interface.Textures;
using Dalamud.Interface.Textures.TextureWraps;
using Dalamud.Utility;
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;

namespace Craftimizer.Utils;

public static class IconManager
public interface ITextureIcon
{
public static ISharedImmediateTexture GetIcon(uint id, bool isHq = false)
ISharedImmediateTexture Source { get; }

Vector2? Dimensions { get; }

float? AspectRatio => Dimensions is { } d ? d.X / d.Y : null;

nint ImGuiHandle { get; }
}

public interface ILoadedTextureIcon : ITextureIcon, IDisposable { }

public sealed class IconManager : IDisposable
{
private sealed class LoadedIcon : ILoadedTextureIcon
{
// 10: DXGI_FORMAT_R16G16B16A16_FLOAT
public static IDalamudTextureWrap EmptyTexture { get; } = Service.TextureProvider.CreateEmpty(new(4, 4, 10), false, false);

public ISharedImmediateTexture Source { get; }

public Vector2? Dimensions => GetWrap()?.Size;

public nint ImGuiHandle => GetWrapOrEmpty().ImGuiHandle;

private Task<IDalamudTextureWrap> TextureWrapTask { get; }
private CancellationTokenSource DisposeToken { get; }

public LoadedIcon(ISharedImmediateTexture source)
{
Source = source;
DisposeToken = new();
TextureWrapTask = source.RentAsync(DisposeToken.Token);
}

public IDalamudTextureWrap? GetWrap()
{
if (TextureWrapTask.IsCompletedSuccessfully)
return TextureWrapTask.Result;
return null;
}

public IDalamudTextureWrap GetWrapOrEmpty() => GetWrap() ?? EmptyTexture;

public void Dispose()
{
DisposeToken.Cancel();
TextureWrapTask.ToContentDisposedTask(true).Wait();
}
}

// TODO: Unload when unused, but with a custom timer?

Check warning on line 66 in Craftimizer/Utils/IconManager.cs

View workflow job for this annotation

GitHub Actions / build

TODO Unload when unused, but with a custom timer? (https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0026.md)

Check warning on line 66 in Craftimizer/Utils/IconManager.cs

View workflow job for this annotation

GitHub Actions / build

TODO Unload when unused, but with a custom timer? (https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0026.md)
private sealed class CachedIcon : ITextureIcon
{
return Service.TextureProvider.GetFromGameIcon(new GameIconLookup(id, itemHq: isHq));
private LoadedIcon Base { get; }

public ISharedImmediateTexture Source => Base.Source;

public Vector2? Dimensions => Base.Dimensions;

public nint ImGuiHandle => Base.ImGuiHandle;

public CachedIcon(ISharedImmediateTexture source)
{
Base = new(source);
}

public void Release()
{
Base.Dispose();
}
}

public static ISharedImmediateTexture GetTexture(string path)
private Dictionary<(uint Id, bool IsHq), CachedIcon> IconCache { get; } = [];
private Dictionary<string, CachedIcon> AssemblyTextureCache { get; } = [];

private static ISharedImmediateTexture GetIconInternal(uint id, bool isHq = false) =>
Service.TextureProvider.GetFromGameIcon(new GameIconLookup(id, itemHq: isHq));

private static ISharedImmediateTexture GetAssemblyTextureInternal(string filename) =>
Service.TextureProvider.GetFromManifestResource(Assembly.GetExecutingAssembly(), $"Craftimizer.{filename}");

public static ILoadedTextureIcon GetIcon(uint id, bool isHq = false) =>
new LoadedIcon(GetIconInternal(id, isHq));

public static ILoadedTextureIcon GetAssemblyTexture(string filename) =>
new LoadedIcon(GetAssemblyTextureInternal(filename));

public ITextureIcon GetIconCached(uint id, bool isHq = false)
{
return Service.TextureProvider.GetFromGame(path);
if (IconCache.TryGetValue((id, isHq), out var icon))
return icon;
return IconCache[(id, isHq)] = new(GetIconInternal(id, isHq));
}

public static ISharedImmediateTexture GetAssemblyTexture(string filename)
public ITextureIcon GetAssemblyTextureCached(string filename)
{
return Service.TextureProvider.GetFromManifestResource(Assembly.GetExecutingAssembly(), $"Craftimizer.{filename}");
if (AssemblyTextureCache.TryGetValue(filename, out var texture))
return texture;
return AssemblyTextureCache[filename] = new(GetAssemblyTextureInternal(filename));
}

public static nint GetHandle(this ISharedImmediateTexture me) =>
me.GetWrapOrEmpty().ImGuiHandle;
public void Dispose()
{
foreach (var value in IconCache.Values)
value.Release();
foreach (var value in AssemblyTextureCache.Values)
value.Release();
}
}
Loading

1 comment on commit 716fa55

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: 716fa55 Previous: 7ad073a Ratio
Craftimizer.Benchmark.Bench.Solve(State: 7BAA81C9, Config: B4739BA6) 103533140 ns (± 792318.6109135642)
Craftimizer.Benchmark.Bench.Solve(State: 9840DD62, Config: B4739BA6) 92944338.88888887 ns (± 960207.989780114)

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.