wxWidgets Integration with OgreNext Sample Framework

Discussion area about developing with Ogre-Next (2.1, 2.2 and beyond)


Post Reply
clieb745
Gnoblar
Posts: 1
Joined: Sun Jun 05, 2022 7:06 pm
x 1

wxWidgets Integration with OgreNext Sample Framework

Post by clieb745 »

There hasn’t been much documentation in the way of integrating Ogre 2+ with wxWidgets. I’ve done some research to try and figure out how to display Ogre inside an wxPanel and have successfully created a basic proof of concept that runs on Windows and Linux. I’d like to show how these systems could be combined to create a CAD-like application from mostly existing Ogre and wxWidgets sample code.

The Ogre sample framework contains a lot of useful structure and existing demos to get us started, even if we may want to override it in the future with our own variant I like to include it here as part of the Ogre 2+ framework. While we may not need to use SDL2 for user input in the final application, it can be combined with wxWidgets by replacing the call to SDL_CreateWindow(…) with SDL_CreateWindowFrom((void)m_panel1->GetHandle()) and this way Ogre renders directly to the wxPanel. There is no need for wxGLCanvas integration and this works fully with Direct3D and OpenGL RenderSystems and partially with Vulkan(1). On Windows, that is all was that was needed to display Ogre inside a wxWidgets application panel, but to get this working on Linux/wxGTK there was some additional code to get it working (*2). Disabling window grabbing was also necessary on Linux, while it seems to still sort of work on Win32.

Since the GraphicsSystem::initialize function is not virtual we need to rely on a different function to initialize and deinitialize Ogre and we want the ogre pointers shared with the wx application so we can manipulate the Ogre objects when responding to wxWidgets events. Inheriting from wxPanel and Demo::GraphicsSystem is possible, but I prefer making the inherited wxPanel class a friend class of the inherited Demo::GraphicsSystem class rather than using multiple inheritance.

The render loop needs to be called from wxIdleEvent that can be triggered using wxQueueEvent, otherwise we end up with inconsistent and choppy UI that doesn’t always respond to input. I’ve tried several variations of using wxThread but the rendering thread takes over and the wxWidgets application suffers from starvation unless you use wxCondition and wxMutex primitives to sync up and that code gets complicated when wxIdleEvent provides just what is needed for a smooth UI that also renders Ogre in real-time.

In order to copy and re-use most of the EmptyProject tutorial application, using IMPLEMENT_APP_NO_MAIN(…) is the best option for integrating with SDL2. The problem I was running into on Linux was that SDL_Init needs to be called before wxEntry(…) and SDL_Quit() should go after wxPanel::Destroy. It takes a bit of work to make sure the initialization and de-initialization methods get called for a clean application exit depending on how the init and render functions are being sync’d. This is mostly re-using code from the singleThreadedMainLoop code but it should be possible to have the logic system run in a separate thread as long as the render update barrier is also shared by the wxIdleEvent.

(*1) Instead of using the wxPanel surface to render Ogre, SDL_CreateWindowFrom(…) is creating a new window when selecting the Vulkan render system.

(*2)

Code: Select all

// The following code is needed to support Linux/wxGTK integration with SDL

#ifdef __WXGTK__
#include "gdk/gdkprivate.h"
#include <GL/glx.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#endif


#if defined(__WXGTK__)
	// GTK Workaround needed
	GtkWidget* widget = (GtkWidget*)m_panel1->m_wxwindow;
	gtk_widget_realize(widget); // Mandatory. Otherwise, a segfault happens.
	std::stringstream handleStream;
	Display* display =
		GDK_WINDOW_XDISPLAY(m_panel1->GTKGetDrawingWindow());
	Window wid = GDK_WINDOW_XID(m_panel1->GTKGetDrawingWindow());
	std::string displayStr = DisplayString(display);
	displayStr = displayStr.substr(1, (displayStr.find(".", 0) - 1));
	handleStream << displayStr << ':' << DefaultScreen(display) << ':' << wid;
	winHandle = handleStream.str();

#elif defined(SDL_VIDEO_DRIVER_WINDOWS)
	winHandle =
		Ogre::StringConverter::toString((uintptr_t)wmInfo.info.win.window);
#endif

(*3) In the custom graphics system initialization routine make sure to set inputHandler->setGrabMousePointer(false).
Image

Image

Image

Image

Attachments
WxOgre2EmptyProject.zip
wxWidgets OgreNext POC source code
(14.78 KiB) Downloaded 29 times
Post Reply