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

Add ImDrawCmd.UserCallback support #11

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions ImGuiScene/ImGui_Impl/Renderers/IImGuiRenderer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using ImGuiNET;

namespace ImGuiScene
{
Expand All @@ -7,10 +8,16 @@ namespace ImGuiScene
/// </summary>
public interface IImGuiRenderer
{
public delegate void DrawCmdUserCallbackDelegate(ImDrawDataPtr drawData, ImDrawCmdPtr drawCmd);

public nint ResetDrawCmdUserCallback { get; }

// FIXME - probably a better way to do this than params object[] !
void Init(params object[] initParams);
void Shutdown();
void NewFrame();
void RenderDrawData(ImGuiNET.ImDrawDataPtr drawData);
public nint AddDrawCmdUserCallback(DrawCmdUserCallbackDelegate @delegate);
public void RemoveDrawCmdUserCallback(DrawCmdUserCallbackDelegate @delegate);
}
}
52 changes: 43 additions & 9 deletions ImGuiScene/ImGui_Impl/Renderers/ImGui_Impl_DX11.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using SharpDX.Mathematics.Interop;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
Expand All @@ -26,6 +27,7 @@ namespace ImGuiScene
/// </summary>
public unsafe class ImGui_Impl_DX11 : IImGuiRenderer
{
private readonly Dictionary<nint, IImGuiRenderer.DrawCmdUserCallbackDelegate> _drawCallbacks = new();
private IntPtr _renderNamePtr;
private Device _device;
private DeviceContext _deviceContext;
Expand All @@ -46,6 +48,8 @@ public unsafe class ImGui_Impl_DX11 : IImGuiRenderer
// so we don't make a temporary object every frame
private RawColor4 _blendColor = new RawColor4(0, 0, 0, 0);

public nint ResetDrawCmdUserCallback { get; private set; }

// TODO: I'll clean this up better later
private class StateBackup : IDisposable
{
Expand Down Expand Up @@ -426,23 +430,31 @@ public void RenderDrawData(ImDrawDataPtr drawData)
for (int cmd = 0; cmd < cmdList.CmdBuffer.Size; cmd++)
{
var pcmd = cmdList.CmdBuffer[cmd];
if (pcmd.UserCallback != IntPtr.Zero)
{
// TODO
throw new NotImplementedException();
}
else

if (pcmd.UserCallback == IntPtr.Zero)
{
// Apply scissor/clipping rectangle
_deviceContext.Rasterizer.SetScissorRectangle((int)(pcmd.ClipRect.X - clipOff.X), (int)(pcmd.ClipRect.Y - clipOff.Y), (int)(pcmd.ClipRect.Z - clipOff.X), (int)(pcmd.ClipRect.W - clipOff.Y));

// Bind texture, Draw
// TODO: might be nice to store samplers for loaded textures so that we can look them up and apply them here
// rather than just always using the font sampler
var textureSrv = ShaderResourceView.FromPointer<ShaderResourceView>(pcmd.TextureId);
var textureSrv = CppObject.FromPointer<ShaderResourceView>(pcmd.TextureId);
_deviceContext.PixelShader.SetShaderResource(0, textureSrv);
_deviceContext.DrawIndexed((int)pcmd.ElemCount, (int)(pcmd.IdxOffset + indexOffset), (int)(pcmd.VtxOffset + vertexOffset));
}
else if (_drawCallbacks.TryGetValue(pcmd.UserCallback, out var cb))
{
// Use custom callback
cb(drawData, pcmd);
}
else
{
Debug.WriteLine(
$"[{nameof(ImGui_Impl_DX11)})] " +
$"((ImDrawData*)0x{(ulong) drawData.NativePtr:X})" +
$"->CmdLists[{n}]" +
$"->CmdBuffer[{cmd}]" +
$".UserCallback (0x{pcmd.UserCallback}:X) is not registered for use.");
}
}

indexOffset += cmdList.IdxBuffer.Size;
Expand Down Expand Up @@ -685,6 +697,7 @@ public void Init(params object[] initParams)

_device = (Device)initParams[0];
_deviceContext = (DeviceContext)initParams[1];
ResetDrawCmdUserCallback = AddDrawCmdUserCallback((drawData, _) => SetupRenderState(drawData));

InitPlatformInterface();

Expand Down Expand Up @@ -715,6 +728,27 @@ public void NewFrame()
}
}

public nint AddDrawCmdUserCallback(IImGuiRenderer.DrawCmdUserCallbackDelegate @delegate)
{
if (this._drawCallbacks.FirstOrDefault(x => x.Value == @delegate).Key is not 0 and var key)
return key;

key = Marshal.GetFunctionPointerForDelegate(@delegate);
this._drawCallbacks.Add(key, @delegate);
return key;
}

public void RemoveDrawCmdUserCallback(IImGuiRenderer.DrawCmdUserCallbackDelegate @delegate)
{
foreach (var key in this._drawCallbacks
.Where(x => x.Value == @delegate)
.Select(x => x.Key)
.ToArray())
{
this._drawCallbacks.Remove(key);
}
}

/** Viewport support **/
private struct ImGuiViewportDataDx11
{
Expand Down
53 changes: 47 additions & 6 deletions ImGuiScene/ImGui_Impl/Renderers/ImGui_Impl_OpenGL3.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Reflection;
using System.Runtime.CompilerServices;
Expand All @@ -18,6 +21,7 @@ public class ImGui_Impl_OpenGL3 : IImGuiRenderer
{
private static GL Gl = Util.Gl;

private readonly Dictionary<nint, IImGuiRenderer.DrawCmdUserCallbackDelegate> _drawCallbacks = new();
private IntPtr _renderNamePtr;
private uint _vertHandle;
private uint _fragHandle;
Expand All @@ -32,6 +36,8 @@ public class ImGui_Impl_OpenGL3 : IImGuiRenderer
private uint _fontTexture;
private uint _vertexArrayObject;

public nint ResetDrawCmdUserCallback { get; private set; }

public void RenderDrawData(ImDrawDataPtr drawData)
{
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
Expand Down Expand Up @@ -98,12 +104,7 @@ public void RenderDrawData(ImDrawDataPtr drawData)
for (var i = 0; i < cmdList.CmdBuffer.Size; i++)
{
var pcmd = cmdList.CmdBuffer[i];
if (pcmd.UserCallback != IntPtr.Zero)
{
// TODO
throw new NotImplementedException();
}
else
if (pcmd.UserCallback == IntPtr.Zero)
{
// Project scissor/clipping rectangles into framebuffer space
var clipRect = new Vector4
Expand All @@ -124,6 +125,23 @@ public void RenderDrawData(ImDrawDataPtr drawData)
Gl.DrawElementsBaseVertex(PrimitiveType.Triangles, pcmd.ElemCount, DrawElementsType.UnsignedShort, (IntPtr)(pcmd.IdxOffset * sizeof(short)), (int)pcmd.VtxOffset);
}
}
else if (_drawCallbacks.TryGetValue(pcmd.UserCallback, out var cb))
{
// Use custom callback
cb(drawData, pcmd);
}
else
{
unsafe
{
Debug.WriteLine(
$"[{nameof(ImGui_Impl_DX11)})] " +
$"((ImDrawData*)0x{(ulong) drawData.NativePtr:X})" +
$"->CmdLists[{n}]" +
$"->CmdBuffer[{i}]" +
$".UserCallback (0x{pcmd.UserCallback}:X) is not registered for use.");
}
}
}
}

Expand Down Expand Up @@ -188,6 +206,8 @@ public void Init(params object[] initParams)
io.NativePtr->BackendRendererName = (byte*)_renderNamePtr.ToPointer();
}

ResetDrawCmdUserCallback = AddDrawCmdUserCallback((drawData, _) => SetupRenderState(drawData));

// literally nothing else in the source implementation of this function is useful
}

Expand All @@ -210,6 +230,27 @@ public void NewFrame()
}
}

public nint AddDrawCmdUserCallback(IImGuiRenderer.DrawCmdUserCallbackDelegate @delegate)
{
if (this._drawCallbacks.FirstOrDefault(x => x.Value == @delegate).Key is not 0 and var key)
return key;

key = Marshal.GetFunctionPointerForDelegate(@delegate);
this._drawCallbacks.Add(key, @delegate);
return key;
}

public void RemoveDrawCmdUserCallback(IImGuiRenderer.DrawCmdUserCallbackDelegate @delegate)
{
foreach (var key in this._drawCallbacks
.Where(x => x.Value == @delegate)
.Select(x => x.Key)
.ToArray())
{
this._drawCallbacks.Remove(key);
}
}

private void SetupRenderState(ImDrawDataPtr drawData)
{
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
Expand Down
16 changes: 9 additions & 7 deletions ImGuiScene/RawDX11Scene.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ namespace ImGuiScene
public sealed class RawDX11Scene : IDisposable
{
public Device Device { get; private set; }
public DeviceContext DeviceContext { get; private set; }
public IntPtr WindowHandlePtr { get; private set; }
public SwapChain SwapChain { get; private set; }

Expand All @@ -28,7 +29,6 @@ public bool UpdateCursor
set => this.imguiInput.UpdateCursor = value;
}

private DeviceContext deviceContext;
private RenderTargetView rtv;

private int targetWidth;
Expand Down Expand Up @@ -84,9 +84,11 @@ public RawDX11Scene(IntPtr nativeDevice, IntPtr nativeSwapChain)
Initialize();
}

public IImGuiRenderer Renderer => this.imguiRenderer;

private void Initialize()
{
this.deviceContext = this.Device.ImmediateContext;
this.DeviceContext = this.Device.ImmediateContext;

using (var backbuffer = this.SwapChain.GetBackBuffer<Texture2D>(0))
{
Expand All @@ -113,7 +115,7 @@ private void InitializeImGui()

ImGui.GetIO().ConfigFlags |= ImGuiConfigFlags.DockingEnable | ImGuiConfigFlags.ViewportsEnable;

this.imguiRenderer.Init(this.Device, this.deviceContext);
this.imguiRenderer.Init(this.Device, this.DeviceContext);
this.imguiInput = new ImGui_Input_Impl_Direct(WindowHandlePtr);
}

Expand All @@ -131,7 +133,7 @@ private void InitializeImGui()

public void Render()
{
this.deviceContext.OutputMerger.SetRenderTargets(this.rtv);
this.DeviceContext.OutputMerger.SetRenderTargets(this.rtv);

this.imguiRenderer.NewFrame();
this.OnNewRenderFrame?.Invoke();
Expand All @@ -146,14 +148,14 @@ public void Render()
ImGui.Render();

this.imguiRenderer.RenderDrawData(ImGui.GetDrawData());
this.deviceContext.OutputMerger.SetRenderTargets((RenderTargetView)null);
this.DeviceContext.OutputMerger.SetRenderTargets((RenderTargetView)null);
ImGui.UpdatePlatformWindows();
ImGui.RenderPlatformWindowsDefault();
}

public void OnPreResize()
{
this.deviceContext.OutputMerger.SetRenderTargets((RenderTargetView)null);
this.DeviceContext.OutputMerger.SetRenderTargets((RenderTargetView)null);

this.rtv?.Dispose();
this.rtv = null;
Expand Down Expand Up @@ -276,7 +278,7 @@ public byte[] CaptureScreenshot()

using (var tex = new Texture2D(this.Device, desc))
{
this.deviceContext.CopyResource(backBuffer, tex);
this.DeviceContext.CopyResource(backBuffer, tex);
using (var surf = tex.QueryInterface<Surface>())
{
var map = surf.Map(SharpDX.DXGI.MapFlags.Read, out DataStream dataStream);
Expand Down