[2.2] How I integrated ImGui with Ogre 2.2

Design / architecture / roadmap discussions related to future of Ogre3D (version 2.0 and above)
Post Reply
rujialiu
Greenskin
Posts: 140
Joined: Mon May 09, 2016 8:21 am
x 11

[2.2] How I integrated ImGui with Ogre 2.2

Post by rujialiu » Thu Sep 13, 2018 3:21 am

Dear all,

As slicky requested, here is how I integrated ImGui with Ogre 2.2. Note that I've only implemented DX11, but it should be similar for OpenGL.

Code: Select all

#include "OgreImGuiBindings.h"

#include "OgreRoot.h"
#include "OgreWindow.h"
#include "OgreRenderPassDescriptor.h"

#include "imgui.h"
#include "imgui_impl_dx11.h"

#include <d3d11_1.h>

static Ogre::Window *g_ogreRenderWindow = nullptr;
static ID3D11Device*           g_pd3dDevice = nullptr;
static ID3D11DeviceContext*    g_pImmediateContext = nullptr;

static Ogre::RenderPassDescriptor *renderPassDesc = nullptr;

static void beginRenderPassDescriptor() {
	Ogre::RenderSystem* system = Ogre::Root::getSingleton().getRenderSystem();
	if (!renderPassDesc) {
		renderPassDesc = system->createRenderPassDescriptor();
		renderPassDesc->mColour[0].texture = g_ogreRenderWindow->getTexture();
		renderPassDesc->mColour[0].loadAction = Ogre::LoadAction::Load;
		renderPassDesc->mColour[0].storeAction = Ogre::StoreAction::StoreOrResolve;
		renderPassDesc->mDepth.texture = g_ogreRenderWindow->getDepthBuffer();
		renderPassDesc->mDepth.loadAction = Ogre::LoadAction::Load;
		renderPassDesc->mDepth.storeAction = Ogre::StoreAction::DontCare;
		renderPassDesc->mStencil.texture = g_ogreRenderWindow->getStencilBuffer();
		renderPassDesc->mStencil.loadAction = Ogre::LoadAction::Load;
		renderPassDesc->mStencil.storeAction = Ogre::StoreAction::DontCare;
		renderPassDesc->entriesModified(Ogre::RenderPassDescriptor::All);
	}
	Ogre::Vector4 viewportSize(0, 0, 1, 1);
	Ogre::Vector4 scissors(0, 0, 1, 1);
	system->beginRenderPassDescriptor(renderPassDesc, g_ogreRenderWindow->getTexture(), viewportSize, scissors, false, false);
}

static void endRenderPassDescriptor() {
	Ogre::RenderSystem* system = Ogre::Root::getSingleton().getRenderSystem();
	system->endRenderPassDescriptor();
}

void ImGui_NewFrame() {
	ImGui_ImplDX11_NewFrame();
}

void ImGui_Render() {
	beginRenderPassDescriptor();
	ImGui::Render();
	endRenderPassDescriptor();
}

extern LRESULT ImGui_ImplDX11_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

void ImGui_Init(void* renderWindow)
{
	g_ogreRenderWindow = (Ogre::Window*)renderWindow;

	g_pd3dDevice = nullptr;
	g_pImmediateContext = nullptr;

	g_ogreRenderWindow->getCustomAttribute("D3DDEVICE", &g_pd3dDevice);
	g_pd3dDevice->GetImmediateContext(&g_pImmediateContext);

	g_ogreRenderWindow->getCustomAttribute("D3DDEVICE", &g_pd3dDevice);

	HWND hwnd = 0;
	g_ogreRenderWindow->getCustomAttribute("WINDOW", &hwnd);

	ImGui_ImplDX11_Init(hwnd, g_pd3dDevice, g_pImmediateContext);
}

void ImGui_Shutdown()
{
	Ogre::RenderSystem* system = Ogre::Root::getSingleton().getRenderSystem();
	system->destroyRenderPassDescriptor(renderPassDesc);
	renderPassDesc = nullptr;

	ImGui_ImplDX11_Shutdown();
}

First, after you created the render window, call ImGui_Init(renderWindow). Then in the main loop, call ImGui_NewFrame() first, then do message pump, then call renderOneFrame(). In frameRenderQueued(), call ImGui_Render() at the beginning.

In order to support keyboard/mouse input, you also need to call ImGui_ImplDX11_WndProcHandler() at the beginning of your windowProc.

One tricky part is when your mouse clikced in ImGui's window, it should not be passed to Ogre anymore. Here is how I solve this:

Code: Select all

    LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        if (ImGui_ImplDX11_WndProcHandler(hWnd, uMsg, wParam, lParam)) {
            if (ImGui::IsAnyWindowHovered()) return true;
        }
...
1 x

Slicky
Bronze Sponsor
Bronze Sponsor
Posts: 536
Joined: Mon Apr 14, 2003 11:48 pm
Location: Was LA now France
x 11

Re: [2.2] How I integrated ImGui with Ogre 2.2

Post by Slicky » Thu Sep 13, 2018 7:12 am

Thanks for this I will take a look. I was trying using the imguimanager mentioned in other threads. For me on 2.1 I can't get it working yet.
0 x

omar
Gnoblar
Posts: 3
Joined: Mon Apr 11, 2016 1:26 pm
x 1

Re: [2.2] How I integrated ImGui with Ogre 2.2

Post by omar » Fri Sep 14, 2018 10:10 pm

rujialiu wrote:
Thu Sep 13, 2018 3:21 am
One tricky part is when your mouse clikced in ImGui's window, it should not be passed to Ogre anymore. Here is how I solve this:

Code: Select all

        if (ImGui_ImplDX11_WndProcHandler(hWnd, uMsg, wParam, lParam)) {
            if (ImGui::IsAnyWindowHovered()) return true;
        }
...
This is the wrong way to test for this.
See the first entry in the dear imgui FAQ, "How can I tell whether to dispatch mouse/keyboard to imgui or to my application?"
You should be testing the io.WantCaptureMouse flag for mouse inputs, etc.
1 x

rujialiu
Greenskin
Posts: 140
Joined: Mon May 09, 2016 8:21 am
x 11

Re: [2.2] How I integrated ImGui with Ogre 2.2

Post by rujialiu » Sat Sep 15, 2018 1:40 am

omar wrote:
Fri Sep 14, 2018 10:10 pm
This is the wrong way to test for this.
See the first entry in the dear imgui FAQ, "How can I tell whether to dispatch mouse/keyboard to imgui or to my application?"
You should be testing the io.WantCaptureMouse flag for mouse inputs, etc.
Thanks!
0 x

Slicky
Bronze Sponsor
Bronze Sponsor
Posts: 536
Joined: Mon Apr 14, 2003 11:48 pm
Location: Was LA now France
x 11

Re: [2.2] How I integrated ImGui with Ogre 2.2

Post by Slicky » Mon Sep 24, 2018 9:34 am

I'm still trying to get this to work. In your approach do you just have your imguibindings source and header file and that's it other than calls to ImGui itself?
0 x

rujialiu
Greenskin
Posts: 140
Joined: Mon May 09, 2016 8:21 am
x 11

Re: [2.2] How I integrated ImGui with Ogre 2.2

Post by rujialiu » Mon Sep 24, 2018 3:52 pm

Slicky wrote:
Mon Sep 24, 2018 9:34 am
I'm still trying to get this to work. In your approach do you just have your imguibindings source and header file and that's it other than calls to ImGui itself?
To create/modify the actual UI, of course you still need to call ImGui's itself :)
But other housekeeping stuffs are handled in the binding source/header files. To be more clear:
  • After you created the render window, call ImGui_Init(renderWindow).
  • In the main loop, call ImGui_NewFrame() first, then do message pump, then call renderOneFrame().
  • In frameRenderQueued(), call ImGui_Render() at the beginning.
  • When you want to destroy the UI system, call ImGui_Shutdown().
  • In order to support keyboard/mouse input, call ImGui_ImplDX11_WndProcHandler() at the beginning of your windowProc. See omar's reply for the correct way to test whether to dispatch mouse/keyboard to ImGui.
All of ImGui_Init(), ImGui_NewFrame() and ImGui_Render() are wrapper functions provided by my binding, but ImGui_ImplDX11_WndProcHandler() is provided by ImGui.
0 x

Post Reply