diff --git a/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj b/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj
index 67ca26dee2..d7eb8499cb 100644
--- a/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj
+++ b/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj
@@ -50,4 +50,10 @@
false
+
+
+
+ Always
+
+
diff --git a/Dalamud.CorePlugin/Dalamud.CorePlugin.json b/Dalamud.CorePlugin/Dalamud.CorePlugin.json
new file mode 100644
index 0000000000..7db669a73c
--- /dev/null
+++ b/Dalamud.CorePlugin/Dalamud.CorePlugin.json
@@ -0,0 +1,9 @@
+{
+ "Author": "Dalamud Maintainers",
+ "Name": "CorePlugin",
+ "Punchline": "Testbed for developing Dalamud features.",
+ "Description": "Develop and debug internal Dalamud features using CorePlugin. You have full access to all types in Dalamud assembly.",
+ "InternalName": "CorePlugin",
+ "ApplicableVersion": "any",
+ "Tags": []
+}
diff --git a/Dalamud.CorePlugin/PluginImpl.cs b/Dalamud.CorePlugin/PluginImpl.cs
index ef99f6def6..f5ff92537f 100644
--- a/Dalamud.CorePlugin/PluginImpl.cs
+++ b/Dalamud.CorePlugin/PluginImpl.cs
@@ -56,7 +56,7 @@ public void Dispose()
///
/// Dalamud plugin interface.
/// Logging service.
- public PluginImpl(DalamudPluginInterface pluginInterface, IPluginLog log)
+ public PluginImpl(DalamudPluginInterface pluginInterface, IDataManager dataManager, ITextureProvider textureProvider, IPluginLog log)
{
try
{
@@ -64,7 +64,7 @@ public PluginImpl(DalamudPluginInterface pluginInterface, IPluginLog log)
this.Interface = pluginInterface;
this.pluginLog = log;
- this.windowSystem.AddWindow(new PluginWindow());
+ this.windowSystem.AddWindow(new PluginWindow(pluginInterface.UiBuilder, dataManager, textureProvider));
this.Interface.UiBuilder.Draw += this.OnDraw;
this.Interface.UiBuilder.OpenConfigUi += this.OnOpenConfigUi;
diff --git a/Dalamud.CorePlugin/PluginWindow.cs b/Dalamud.CorePlugin/PluginWindow.cs
index 27be82f41e..6430b04245 100644
--- a/Dalamud.CorePlugin/PluginWindow.cs
+++ b/Dalamud.CorePlugin/PluginWindow.cs
@@ -1,8 +1,14 @@
using System;
-using System.Numerics;
-
+using System.IO;
+using Dalamud.Interface;
+using Dalamud.Interface.Internal;
using Dalamud.Interface.Windowing;
+using Dalamud.Plugin.Services;
using ImGuiNET;
+using Lumina.Data.Files;
+using SharpDX;
+using SharpDX.Direct3D11;
+using Vector2 = System.Numerics.Vector2;
namespace Dalamud.CorePlugin
{
@@ -11,21 +17,59 @@ namespace Dalamud.CorePlugin
///
internal class PluginWindow : Window, IDisposable
{
+ private readonly UiBuilder uiBuilder;
+ private readonly ITextureProvider textureProvider;
+ private readonly IDalamudTextureWrap tex;
+ private readonly IntPtr callbackId;
+ private readonly Device device;
+ private readonly DeviceContext deviceContext;
+ private readonly PixelShader pixelShader;
+ private readonly SamplerState fontSampler;
+
///
/// Initializes a new instance of the class.
///
- public PluginWindow()
+ public PluginWindow(UiBuilder uiBuilder, IDataManager dataManager, ITextureProvider textureProvider)
: base("CorePlugin")
{
+ this.uiBuilder = uiBuilder;
+ this.textureProvider = textureProvider;
this.IsOpen = true;
this.Size = new Vector2(810, 520);
this.SizeCondition = ImGuiCond.FirstUseEver;
+
+ this.tex = this.textureProvider.GetTexture(dataManager.GetFile("chara/monster/m0361/obj/body/b0001/texture/v01_m0361b0001_n.tex")!);
+ this.callbackId = this.uiBuilder.AddImGuiDrawCmdUserCallback(this.DrawCmdUserCallback);
+ this.device = CppObject.FromPointer(uiBuilder.DeviceNativePointer);
+ this.deviceContext = CppObject.FromPointer(uiBuilder.DeviceContextNativePointer);
+ this.pixelShader = new PixelShader(this.device, File.ReadAllBytes(@"Z:\test.fxc"));
+ this.fontSampler = new SamplerState(this.device, new SamplerStateDescription
+ {
+ Filter = Filter.MinMagMipLinear,
+ AddressU = TextureAddressMode.Wrap,
+ AddressV = TextureAddressMode.Wrap,
+ AddressW = TextureAddressMode.Wrap,
+ MipLodBias = 0,
+ ComparisonFunction = Comparison.Always,
+ MinimumLod = 0,
+ MaximumLod = 0,
+ });
+ }
+
+ private void DrawCmdUserCallback(ImDrawDataPtr drawData, ImDrawCmdPtr drawCmd)
+ {
+ this.deviceContext.PixelShader.Set(this.pixelShader);
+ this.deviceContext.PixelShader.SetSampler(0, this.fontSampler);
}
///
public void Dispose()
{
+ this.uiBuilder.RemoveImGuiDrawCmdUserCallback(this.DrawCmdUserCallback);
+ this.tex.Dispose();
+ this.pixelShader.Dispose();
+ this.fontSampler.Dispose();
}
///
@@ -36,6 +80,15 @@ public override void OnOpen()
///
public override void Draw()
{
+ var drawList = ImGui.GetWindowDrawList();
+ drawList.AddCallback(this.callbackId, nint.Zero);
+ ImGui.Image(this.tex.ImGuiHandle, new(512, 512), new(1, 0), new(2, 1));
+ ImGui.SameLine();
+ ImGui.Image(this.tex.ImGuiHandle, new(512, 512), new(2, 0), new(3, 1));
+ ImGui.Image(this.tex.ImGuiHandle, new(512, 512), new(3, 0), new(4, 1));
+ ImGui.SameLine();
+ ImGui.Image(this.tex.ImGuiHandle, new(512, 512), new(4, 0), new(5, 1));
+ drawList.AddCallback(this.uiBuilder.ImGuiResetDrawCmdUserCallback, nint.Zero);
}
}
}
diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs
index d5394fe8d9..1f2d85f070 100644
--- a/Dalamud/Interface/Internal/InterfaceManager.cs
+++ b/Dalamud/Interface/Internal/InterfaceManager.cs
@@ -149,10 +149,20 @@ private InterfaceManager()
public ImGuiIOPtr LastImGuiIoPtr { get; set; }
///
- /// Gets the D3D11 device instance.
+ /// Gets the ImGuiRenderer from ImGuiScene.
+ ///
+ public IImGuiRenderer? ImGuiRenderer => this.scene?.Renderer;
+
+ ///
+ /// Gets the D3D11 device instance. Note that the reference count is not increased.
///
public SharpDX.Direct3D11.Device? Device => this.scene?.Device;
+ ///
+ /// Gets the D3D11 device context. Note that the reference count is not increased.
+ ///
+ public DeviceContext? DeviceContext => this.scene?.DeviceContext;
+
///
/// Gets the address handle to the main process window.
///
diff --git a/Dalamud/Interface/UiBuilder.cs b/Dalamud/Interface/UiBuilder.cs
index dd2e5bad38..da1a4cecbd 100644
--- a/Dalamud/Interface/UiBuilder.cs
+++ b/Dalamud/Interface/UiBuilder.cs
@@ -16,7 +16,6 @@
using ImGuiNET;
using ImGuiScene;
using Serilog;
-using SharpDX.Direct3D11;
namespace Dalamud.Interface;
@@ -32,6 +31,8 @@ public sealed class UiBuilder : IDisposable
private readonly InterfaceManager interfaceManager = Service.Get();
private readonly GameFontManager gameFontManager = Service.Get();
+ private readonly Dictionary drawCmdUserCallbackDelegates = new();
+
[ServiceManager.ServiceDependency]
private readonly DalamudConfiguration configuration = Service.Get();
@@ -122,9 +123,34 @@ internal UiBuilder(string namespaceName)
public static ImFontPtr MonoFont => InterfaceManager.MonoFont;
///
- /// Gets the game's active Direct3D device.
+ /// Gets the game's active D3D11 device instance. Note that the reference count is not increased.
+ ///
+ public SharpDX.Direct3D11.Device? Device => this.InterfaceManagerWithScene?.Device;
+
+ ///
+ /// Gets the game's active D3D11 device context. Note that the reference count is not increased.
+ ///
+ public SharpDX.Direct3D11.DeviceContext? DeviceContext => this.InterfaceManagerWithScene?.DeviceContext;
+
+ ///
+ /// Gets the native pointer of the game's active D3D11 device instance.
+ /// Note that the reference count is not increased.
+ ///
+ public nint DeviceNativePointer => this.Device?.NativePointer ?? nint.Zero;
+
+ ///
+ /// Gets the native pointer of the game's active D3D11 device context.
+ /// Note that the reference count is not increased.
+ ///
+ public nint DeviceContextNativePointer => this.DeviceContext?.NativePointer ?? nint.Zero;
+
+ ///
+ /// Gets the ImGui DrawCmd callback for resetting the render parameters.
///
- public Device Device => this.InterfaceManagerWithScene.Device!;
+ /// When UI is not yet ready.
+ public nint ImGuiResetDrawCmdUserCallback =>
+ this.interfaceManager.ImGuiRenderer?.ResetDrawCmdUserCallback
+ ?? throw new InvalidOperationException("Renderer is not yet ready.");
///
/// Gets the game's main window handle.
@@ -230,6 +256,36 @@ public bool CutsceneActive
private Task InterfaceManagerWithSceneAsync =>
Service.GetAsync().ContinueWith(task => task.Result.Manager);
+ ///
+ /// Adds a callback that will be called on rendering a texture with set.
+ ///
+ /// The callback.
+ /// The value to use for .
+ /// If UI is not yet ready.
+ public nint AddImGuiDrawCmdUserCallback(IImGuiRenderer.DrawCmdUserCallbackDelegate cb)
+ {
+ if (this.drawCmdUserCallbackDelegates.TryGetValue(cb, out var p))
+ return p;
+
+ if (this.interfaceManager.ImGuiRenderer is not { } renderer)
+ throw new InvalidOperationException("Renderer is not yet ready.");
+
+ this.drawCmdUserCallbackDelegates.Add(cb, p = renderer.AddDrawCmdUserCallback(cb));
+ return p;
+ }
+
+ ///
+ /// Removes a callback that will be called on rendering a texture with set.
+ ///
+ /// The callback.
+ public void RemoveImGuiDrawCmdUserCallback(IImGuiRenderer.DrawCmdUserCallbackDelegate cb)
+ {
+ // Either it's not ready and nothing could have been already added yet,
+ // or it's destructing down and we don't care anymore
+ this.drawCmdUserCallbackDelegates.Remove(cb);
+ this.interfaceManager.ImGuiRenderer?.RemoveDrawCmdUserCallback(cb);
+ }
+
///
/// Loads an image from the specified file.
///
@@ -397,6 +453,8 @@ void IDisposable.Dispose()
this.interfaceManager.Draw -= this.OnDraw;
this.interfaceManager.BuildFonts -= this.OnBuildFonts;
this.interfaceManager.ResizeBuffers -= this.OnResizeBuffers;
+ foreach (var cb in this.drawCmdUserCallbackDelegates.Keys)
+ this.interfaceManager.ImGuiRenderer?.RemoveDrawCmdUserCallback(cb);
}
///
diff --git a/lib/ImGuiScene b/lib/ImGuiScene
index 2f37349ffd..7dbaf3ba9f 160000
--- a/lib/ImGuiScene
+++ b/lib/ImGuiScene
@@ -1 +1 @@
-Subproject commit 2f37349ffd778561a1103a650683116c43edc86c
+Subproject commit 7dbaf3ba9fd115b0e8755da1a1c30fe910b90ea6