JSandusky / ImGuiCLI

C++/CLI wrapper for DearImGui Viewports branch
MIT License
6 stars 3 forks source link

ImGuiCLI

WARNING: this is a 4 hour mash-together project. Really just a viability test.

C++/CLI wrapper for DearImGui Viewports branch, specifically for MonoGame.

Mashes the Dear ImGui Win32 DirectX11 demo into a C++/CLI wrapper. The crap toss is found in class ImGuiContext located in ImGuiContext.h/.cpp.

class ImGuiCli can be used with vanilla ImGui (some extension types will need to be ripped out, nothing major). Located in ImGuiCLI.h/.cpp

Mashing the demo is fairly advantageous given the WIP status of the Viewports branch. Updating to the latest only takes around 15 minutes to merge. Once Viewports are part of core Dear ImGui, and thus likely stable, it would be more appropriate to do a proper implementation.

If you don't want to mess with tweaking MonoGame or didn't install C++ support (and thus C++/CLI) with Visual Studio there are Win32 x86 binaries for basic messing around with to see how it all behaves: https://github.com/JSandusky/ImGuiCLI/releases

Deviations

Access is entirely global single-instance.

DearImGui is tweaked to not own the ID3D11Device, ID3D11DeviceContext, or ID3D11RenderTargetView for the main render target (or functions that would try to own those are not called). MonoGame instead passes those to it where needed.

Enumerations/flags are wrapped as their underscored name (ie. ImGuiDir_) with their values mapped without the prefix.

class ImGuiIO contains some access to Dear ImGui's ImGuiContext menu, largely just convenience as binding the ImGuiContext type isn't necessary for realistic cases (custom widgets should be written in C and bound to C#).

Render/Draw has three functions, two of which are intended to be used together (for periodic updates re-rendering old draw-data).

C# Usage

Complete example gist.

Initialize

   System.IntPtr device = ((SharpDX.Direct3D11.Device)GraphicsDevice.Handle).NativePointer;
    System.IntPtr deviceContext = ((SharpDX.Direct3D11.DeviceContext)GraphicsDevice.ContextHandle).NativePointer;
    System.IntPtr backBuffer = ((SharpDX.Direct3D11.RenderTargetView)GraphicsDevice.BackBuffer).NativePointer;

    var form = ((MonoGame.Framework.WinFormsGameWindow)Window).Form;
    form.SignalNativeMessages.Add(WM_MOUSEHWHEEL);
    form.SignalNativeMessages.Add(WM_KEYDOWN);
    form.SignalNativeMessages.Add(WM_KEYUP);
    form.SignalNativeMessages.Add(WM_CHAR);
    form.NotifyMessage += (o, e) =>
    {
        if (e.Msg == WM_KEYDOWN)
            ImGuiIO.SetKeyState(e.WParam.ToInt32(), true);
        else if (e.Msg == WM_KEYUP)
            ImGuiIO.SetKeyState(e.WParam.ToInt32(), false);
        else if (e.Msg == WM_CHAR && e.WParam.ToInt64() > 0 && e.WParam.ToInt64() < 0x10000)
            ImGuiIO.AddText((ushort)e.WParam.ToInt64());
    };
    imguiContext_ = new ImGuiContext(this.Window.Handle, device, deviceContext, backBuffer);

Run

    float td = gameTime.ElapsedGameTime.Milliseconds / 1000.0f;
    ImGuiIO.DeltaTime = td;
    int newScroll = Mouse.GetState().ScrollWheelValue;
    int scrollDelta = newScroll - scrollValue;
    scrollValue = newScroll;
    if (IsFocused)
        ImGuiIO.SetMouseWheel(scrollDelta / 120.0f);

    ImGuiIO.SetMouseButton(0, Mouse.GetState().LeftButton == ButtonState.Pressed);
    ImGuiIO.SetMouseButton(1, Mouse.GetState().RightButton == ButtonState.Pressed);
    ImGuiIO.SetMouseButton(2, Mouse.GetState().MiddleButton == ButtonState.Pressed);
    switch (ImGuiIO.MouseCursor)
    {
    case ImGuiMouseCursor_.Arrow:
    case ImGuiMouseCursor_.None:
        Mouse.PlatformSetCursor(MouseCursor.Arrow);
        break;
    case ImGuiMouseCursor_.ResizeAll:
        Mouse.PlatformSetCursor(MouseCursor.SizeAll);
        break;
    case ImGuiMouseCursor_.ResizeEW:
        Mouse.PlatformSetCursor(MouseCursor.SizeWE);
        break;
    case ImGuiMouseCursor_.ResizeNS:
        Mouse.PlatformSetCursor(MouseCursor.SizeNS);
        break;
    case ImGuiMouseCursor_.ResizeNESW:
        Mouse.PlatformSetCursor(MouseCursor.SizeNESW);
        break;
    case ImGuiMouseCursor_.ResizeNWSE:
        Mouse.PlatformSetCursor(MouseCursor.SizeNWSE);
        break;
    case ImGuiMouseCursor_.TextInput:
        Mouse.PlatformSetCursor(MouseCursor.IBeam);
        break;
    }
    imguiContext_.NewFrame(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);

    if (ImGuiCli.Begin("Trial window", 0))
    {
        ImGuiCli.Text("Drawing some text");
        ImGuiCli.Checkbox("Checkbox", ref someValue);
    }
    ImGuiCli.End();

        imguiContext_.RenderAndDraw(((SharpDX.Direct3D11.RenderTargetView)GraphicsDevice.BackBuffer).NativePointer);

Shutdown

imguiContext_.Shutdown();

Wrapper Files

MonoGame.Framework.Windows Changes