Using GTKmm 3 and Irrlicht

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Using GTKmm 3 and Irrlicht

Post by chronologicaldot »

Anyone know how to merge Irrlicht with GTKmm 3 ?
I found this answer related to Windows:
By: ebassi
Each applicable GdkDrawable functionality was moved into GdkWindow, once we dropped GdkPixmap from GTK3.
GDK exports gdk_win32_window_get_handle() as a public symbol—but its declaration is not available in a public header, so you’ll have to define it yourself:

Code: Select all

HGDIOBJ       gdk_win32_window_get_handle (GdkWindow *window);
... which is a bummer. I don't know how to implement this.

I thought about just making Irrlicht a separate window and passing clicks in it to the GTK side, but I haven't tested to see if that will work. The downside is that I don't get to have it all on one window.
I haven't tried it yet, but is it possible to instantiate Irrlicht without a window (so I can get Burnings because I guess GL won't work in this case) and draw directly onto a image?
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Using GTKmm 3 and Irrlicht

Post by CuteAlien »

Same thread seems to mention a GDK_WINDOW_HWND macro - maybe you can use that?
Irrlicht seems to have an EIDT_FRAMEBUFFER device (can be set in SIrrlichtCreationParameters::DeviceType and then be passed to createDeviceEx). But I've never tested or used that so I don't really know anything about it so far.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Re: Using GTKmm 3 and Irrlicht

Post by chronologicaldot »

Thank you! That may actually be what I'm looking for.
Talking out loud for anyone else interested... I can try to render on an image inside a GUI element. How to update it (irrDevice->run(), irrVideoDriver->beginScene())?
I guess via this answer, I need to run Irrlicht on a separate thread created within the GUI element that stores and displays the image drawn to. Last I recall, there was some issue with running Irrlicht on a second thread which maybe had to do with loading assets??
Assuming I understand Irrlicht's frame buffer device correctly, I can render first to the frame buffer's image, then copy it to the GUI element image (mutex locking the thing), then sleep for some milliseconds, then loop back around and start over.
A couple of hiccups: 1) If the GUI element is resized, the frame buffer image won't. 2) I'm not sure how to lock a GTK image yet.
I'm checking out this answer.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Using GTKmm 3 and Irrlicht

Post by CuteAlien »

It may be possible to use OpenGL with framebuffer device. In which case you can use rendertargettextures and wouldn't need the framebuffer itself at all.

Irrlicht can be used in a thread. It's just with OpenGL you have to make certain the active thread running Irrlicht does have the context (or enable multithreaded support, but I wouldn't recommend that).
Not sure right now about how that was done with 1.8 but with Irrlich trunk you basically call this when entering the thread

Code: Select all

irrlichtDevice->getContextManager()->activateContext(videoDriver->getExposedVideoData());
and when leaving you thread you release it again with

Code: Select all

irrlichtDevice->getContextManager()->activateContext(irr::video::SExposedVideoData())
Alternatively - don't use threads. Use a timer. I do that in my current app with WTL. Just avoid the element clearing background so it doesn't flicker on stuff like resize and that works rather well. And yeah - tiny flicker maybe on resize, but as long as you don't fill it with white on clear that's hardly noticable and a tiny render delay 1 frame on resize is fine.

But it would be better if you can find out how to get the HWND from GTK and just pass that to Irrlicht. And then refer to Win32Window example. What goes wrong with the defining "HGDIOBJ gdk_win32_window_get_handle (GdkWindow *window);"?
Did you try declaring that (with extern in front probably if you link statically, or likely __declspec(dllimport) when linking dynamically) and then just calling it?
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Re: Using GTKmm 3 and Irrlicht

Post by chronologicaldot »

I checked the code and the frame buffer device (in CIrrDeviceFB.cpp) only supports the software renderers. It makes copying from the video driver to the frame buffer easy.

Thanks for the other notes.
As for gdk_win32_window_get_handle(), I'm currently on Linux, so I can't say that it works or not, but I need to keep that as a reference if and when I code for that.
Via this: I found I need to use get_xid() to fill the X11Window variable of SOpenGLLinux in SExposedVideoData.
get_xid() is actually method on GdkX11.X11Window, not on Gdk.Window. In order to be able to see this method, GdkX11 namespace have to be loaded, e.g. using local GdkX11= lgi.GdkX11. After that, get_xid() method is available, because Gtk.DrawingArea():get_window() is of expected GdkX11.X11Window instead of plain Gdk.Window type.
But I don't yet know where to get the X11Display data from GTK, and last time I messed with the X11Display variable in Irrlicht, Irrlicht seemed to have magically changed it midway through operation, giving me a BadWindow error. (This issue I ran into here when trying to change the icon via SExposedVideoData.)

UPDATE:
I found here that the GdkX11 X11Display contains the method get_xdisplay() for getting the X11Display, but I don't know yet how to reach this class. Still digging.
Related: X11Window, and GDK3 X11Display docs.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Using GTKmm 3 and Irrlicht

Post by CuteAlien »

The bug with changing the X11Display might be fixed now in svn trunk trunk (r6370 - around 5 months ago). GLX and X11 Window had been mixed up.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Re: Using GTKmm 3 and Irrlicht

Post by chronologicaldot »

You're right, it got fixed, so now icons appear.

The FrameBuffer device only supports the software drivers, but it would be nice to have OpenGL, which I believe GTK can do.
I decided to see if I could get the necessary info from gtk for rendering with OpenGL. Unfortunately it's been a major headache trying to track down the info!!
Here's what I came up with thus far:

Code: Select all

#include <cstdio>
#include <irrlicht.h>
#include <glibmm/ustring.h>
//#include <glibmm/main.h> // For SignalIdle/signal_idle()
#include <glibmm.h>
#include <gtkmm/application.h>
#include <gtkmm/window.h>
//#include <gtk-3.0/gdk/gdkx.h> // (Must be after glibmm, gdkmm, and gtkmm headers) For gdk_x11_display_get_xdisplay()
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>  // for GDK_WINDOW_XID
#endif
#ifdef GDK_WINDOWING_WIN32
#include <gdk/gdkwin32.h>  // for GDK_WINDOW_HWND
#endif
#include "HelloWorld.h" // Just contains an empty class that inherits Gtk::Window

HelloWorld* helloWorld;

class IrrSideEventReceiver : public irr::IEventReceiver
{
public:
	bool OnEvent(const irr::SEvent& event)
	{
		std::printf("\nIrrlicht Event");
		// TODO: Pass mouse-click events to GTK side
		return false;
	}
};

class IrrMain {
	irr::IrrlichtDevice* irrDevice;
	irr::SIrrlichtCreationParameters irrParams;
	irr::video::SExposedVideoData irrVideoData;

public:
	IrrMain( irr::SIrrlichtCreationParameters& params, irr::video::SExposedVideoData& vdata )
		: irrDevice()
		, irrParams(params)
		, irrVideoData(vdata)
	{}

	void init()
	{
		irrDevice = irr::createDeviceEx(irrParams);

		if (!irrDevice) throw;

		irr::scene::ILightSceneNode* irrLight = irrDevice->getSceneManager()->addLightSceneNode(
				0, irr::core::vector3df(1,10,2), irr::video::SColor(0xffffffff), 20, 0);

		irr::scene::ICameraSceneNode* irrCam = irrDevice->getSceneManager()->addCameraSceneNode(
				0, irr::core::vector3df(0,5,5), irr::core::vector3df(0,0,0), 1, true);

		irr::scene::ISceneNode* irrCube = irrDevice->getSceneManager()->addCubeSceneNode(
				1, 0, 2, irr::core::vector3df(0,0,0), irr::core::vector3df(0.3,0,0), irr::core::vector3df(1,1,1),
				irr::scene::ECMT_1BUF_12VTX_NA);

		irrDevice->run();

		//while(irrDevice->run()) {
			irrDevice->getVideoDriver()->beginScene(
					true, true, irr::video::SColor(0xff0000ff),
					irrVideoData, 0);
		/*
			irrDevice->getVideoDriver()->beginScene(
					true, true, irr::video::SColor(0xff000000),
					irr::video::SExposedVideoData(), 0);
			irrDevice->getVideoDriver()->endScene();
		*/
		//}
	}
} *irrMain;


void init() {
	irr::SIrrlichtCreationParameters irrParams;
	irr::video::SExposedVideoData irrVideoData;

	GdkWindow* gdk_window = helloWorld->get_window()->gobj();
	if (!gdk_window) throw;
	gulong xid = GDK_WINDOW_XID(gdk_window);

	//irrParams.WindowId = (void*)xid; // Does nothing on Linux
	irrParams.AntiAlias = false;
	irrParams.Bits = 32;
	irrParams.DeviceType = irr::EIDT_X11;
	//irrParams.DeviceType = irr::EIDT_FRAMEBUFFER;
	irrParams.DriverType = irr::video::EDT_OPENGL; // Should test with Burnings first
	//irrParams.DriverType = irr::video::EDT_BURNINGSVIDEO;
	//irrParams.EventReceiver = &iEventReceiver;
	irrParams.Fullscreen = false;
	irrParams.IgnoreInput = true; // TODO: Test without this too
	irrParams.Stencilbuffer = true;
	irrParams.Vsync = false;
	irrParams.WithAlphaChannel = false; // TODO: Test with alpha channel
	gint windowWidth=0, windowHeight=0;
	helloWorld->get_size(windowWidth, windowHeight); // Won't work. Window not initialized
	irrParams.WindowSize = irr::core::dimension2du(windowWidth,windowHeight);

	auto xdisplay = gdk_x11_display_get_xdisplay(helloWorld->get_screen()->get_display()->gobj());
	irrVideoData.OpenGLLinux.X11Display = xdisplay;
	irrVideoData.OpenGLLinux.X11Window = xid;

	irrMain = new IrrMain(irrParams, irrVideoData);
	irrMain->init();
}

int main (int argc, char *argv[])
{
	Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.example"); // @suppress("Invalid arguments")

	helloWorld = new HelloWorld();
	helloWorld->set_size_request(900, 600);

	Glib::signal_idle().connect_once(sigc::slot<void>(&init));

	//Shows the window and returns when it is closed.
	return app->run(*helloWorld);
}
It doesn't work, of course. I get an X BadMatch.
I looked at the implementation of CIrrDeviceLinux::createDriver() and discovered for GL it just assigns the initial window and display to 0 (see line 624). Initial SExposedVideoData are ignored. lol. The result is that a separate window for OpenGL is created even if you are intending to house it in a different one. And I found in CGLXManager::activateContext() that I need an X11Context, which I don't know how to get from GTK, and no one seems to have the answer. Years and years ago, someone created a GLArea class, but it's so outdated and there's little reference for how to use it.

BurningsVideo doesn't complain... but it doesn't render anything either.

At this point, I think the easiest thing is either 1) test if the Frame Buffer option will work (if I'm happy with just the software renderer) or 2) run Irrlicht in a separate window (if I want OpenGL).
Unless someone can figure out what I did wrong...
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Re: Using GTKmm 3 and Irrlicht

Post by chronologicaldot »

Just as I post that, I found Gdk GLContext, but I'm not sure how to use it. I'm guessing I'll need:

Code: Select all

GdkGLContext* context gdk_surface_create_gl_context()
void gdk_gl_context_make_current (  GdkGLContext* context ) /*or*/ gboolean gdk_gl_context_realize( GdkGLContext* context )
GdkGLContext* gdk_gl_context_get_current()
But I don't know how to get to the X11Context from here.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Using GTKmm 3 and Irrlicht

Post by CuteAlien »

Initial SExposedVideoData is ignored, because you pass the Window with SIrrlichtCreationParameters::WindowId. Check line 522 in CIrrDeviceLinux.cpp.
So try with that one.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Re: Using GTKmm 3 and Irrlicht

Post by chronologicaldot »

Tried that. Same issue. But it gives more error messages:

Code: Select all

Irrlicht Engine version 1.9.0
Linux 5.4.0-72-generic #80-Ubuntu SMP Mon Apr 12 17:35:00 UTC 2021 x86_64
Creating X window...
X Error: BadMatch (invalid parameter attributes)
From call : unknown
X Error: GLXBadDrawable
From call : unknown
Context activation failed.
Using renderer: OpenGL 
OpenGL driver version is not 1.2 or better.
GLSL not available.
X Error: BadMatch (invalid parameter attributes)
From call : unknown
Context activation failed.
As you can see in my code, I tried the following:

Code: Select all

	GdkWindow* gdk_window = helloWorld->get_window()->gobj();
	if (!gdk_window) throw;
	gulong xid = GDK_WINDOW_XID(gdk_window);

	irrParams.WindowId = (void*)xid;
Maybe I'm passing the wrong thing? I thought the XWindow as given by the XID, which is also what I gave to irrVideoData.OpenGLLinux.X11Window. Am I wrong?
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Using GTKmm 3 and Irrlicht

Post by CuteAlien »

Should not be xid, but directly the XWindow pointer.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Re: Using GTKmm 3 and Irrlicht

Post by chronologicaldot »

According to this StackOverflow answer, the X Window is typedef XID Window (in X.h in /usr/include/X11). CIrrDeviceLinux line 491 uses XCreateWindow() to make it. The docs on X I found say that XCreateWindow() returns the window ID. So it seems to me I have the right item.

I tried creating a GLXContext, which according to line 360 of CGLXManager.cpp is supposed to go in X11Context. Still didn't work. Here's what I did:

Code: Select all

#include <cstdio>
#include <irrlicht.h>
#include <glibmm/ustring.h>
//#include <glibmm/main.h> // For SignalIdle/signal_idle()
#include <glibmm.h>
#include <gtkmm/application.h>
#include <gtkmm/window.h>
//#include <gtk-3.0/gdk/gdkx.h> // (Must be after glibmm, gdkmm, and gtkmm headers) For gdk_x11_display_get_xdisplay()
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>  // for GDK_WINDOW_XID
#endif
#ifdef GDK_WINDOWING_WIN32
#include <gdk/gdkwin32.h>  // for GDK_WINDOW_HWND
#endif
#include <GL/glx.h>
#include "HelloWorld.h"

HelloWorld* helloWorld;
GLXContext glxContext;

class IrrSideEventReceiver : public irr::IEventReceiver
{
public:
	bool OnEvent(const irr::SEvent& event)
	{
		std::printf("\nIrrlicht Event");
		// TODO: Pass mouse-click events to GTK side
		return false;
	}
};

class IrrMain {
	irr::IrrlichtDevice* irrDevice;
	irr::SIrrlichtCreationParameters irrParams;
	irr::video::SExposedVideoData irrVideoData;

public:
	IrrMain( irr::SIrrlichtCreationParameters& params, irr::video::SExposedVideoData& vdata )
		: irrDevice()
		, irrParams(params)
		, irrVideoData(vdata)
	{}

	void init()
	{
		irrDevice = irr::createDeviceEx(irrParams);

		if (!irrDevice) throw;

		irrDevice->getSceneManager()->addLightSceneNode(
				0, irr::core::vector3df(1,10,2), irr::video::SColor(0xffffffff), 20, 0);

		irrDevice->getSceneManager()->addCameraSceneNode(
				0, irr::core::vector3df(0,5,5), irr::core::vector3df(0,0,0), 1, true);

		irrDevice->getSceneManager()->addCubeSceneNode(
				1, 0, 2, irr::core::vector3df(0,0,0), irr::core::vector3df(0.3,0,0), irr::core::vector3df(1,1,1),
				irr::scene::ECMT_1BUF_12VTX_NA);

		irrDevice->run();

		irrDevice->getVideoDriver()->beginScene(
					true, true, irr::video::SColor(0xff0000ff),
					irrVideoData, 0);

		irrDevice->getSceneManager()->drawAll();
		irrDevice->getVideoDriver()->endScene();
	}
} *irrMain;


void init() {
	irr::SIrrlichtCreationParameters irrParams;
	irr::video::SExposedVideoData irrVideoData;

	GdkWindow* gdk_window = helloWorld->get_window()->gobj();
	if (!gdk_window) throw;
	gulong xid = GDK_WINDOW_XID(gdk_window);

	irrParams.WindowId = (void*)xid; // Does nothing on Linux
	irrParams.AntiAlias = false;
	irrParams.Bits = 32;
	irrParams.DeviceType = irr::EIDT_X11;
	irrParams.DriverType = irr::video::EDT_OPENGL;
	irrParams.Fullscreen = false;
	irrParams.IgnoreInput = true; // TODO: Test without this too
	irrParams.Stencilbuffer = true;
	irrParams.Vsync = false;
	irrParams.WithAlphaChannel = false; // TODO: Test with alpha channel
	gint windowWidth=0, windowHeight=0;
	helloWorld->get_size(windowWidth, windowHeight); // Won't work. Window not initialized
	irrParams.WindowSize = irr::core::dimension2du(windowWidth,windowHeight);

	GLint attr_list[] = {GLX_DOUBLEBUFFER,
					   GLX_RGBA,
					   GLX_DEPTH_SIZE, 16,
					   GLX_RED_SIZE,   8,
					   GLX_GREEN_SIZE, 8,
					   GLX_BLUE_SIZE,  8,
					   None};
	XVisualInfo* visualinfo = glXChooseVisual(GDK_WINDOW_XDISPLAY (gdk_window), gdk_screen_get_number(gdk_window_get_screen (gdk_window)), attr_list);
	glxContext = glXCreateContext (GDK_WINDOW_XDISPLAY (gdk_window), visualinfo, NULL, TRUE);

	auto xdisplay = gdk_x11_display_get_xdisplay(helloWorld->get_screen()->get_display()->gobj());
	irrVideoData.OpenGLLinux.X11Display = xdisplay;
	irrVideoData.OpenGLLinux.X11Window = xid;
	irrVideoData.OpenGLLinux.X11Context = (void*)&glxContext;

	irrMain = new IrrMain(irrParams, irrVideoData);
	irrMain->init();
}

int main (int argc, char *argv[])
{
	Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.example"); // @suppress("Invalid arguments")

	helloWorld = new HelloWorld();
	helloWorld->set_size_request(900, 600);

	Glib::signal_idle().connect_once(sigc::slot<void>(&init));

	//Shows the window and returns when it is closed.
	return app->run(*helloWorld);
}
But it just gives me a GLXBadContext error. Full output:

Code: Select all

Irrlicht Engine version 1.9.0
Linux 5.4.0-72-generic #80-Ubuntu SMP Mon Apr 12 17:35:00 UTC 2021 x86_64
Creating X window...
X Error: BadMatch (invalid parameter attributes)
From call : unknown
X Error: GLXBadDrawable
From call : unknown
Context activation failed.
Using renderer: OpenGL 
OpenGL driver version is not 1.2 or better.
GLSL not available.
X Error: GLXBadContext
From call : unknown
Context activation failed.
As you can see, it's still complaining about the X Window.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Using GTKmm 3 and Irrlicht

Post by CuteAlien »

Right, XID seems to be Window.

Can't get your example working as I got no HelloWorld.h. So I can't debug what's going on. And I don't know enough about this stuff to have an idea without debugging (not sure if I can figure out anything with debugging... but at least I could see where the errors come from etc).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Re: Using GTKmm 3 and Irrlicht

Post by chronologicaldot »

HelloWorld is an empty class inheriting Gtk::Window. Just put this near the top of main.cpp:

Code: Select all

class HelloWorld : public Gtk::Window {};
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Using GTKmm 3 and Irrlicht

Post by CuteAlien »

OK, I can get it to work with some changes.

First - don't use irrVideoData at all for now. I haven't tried with that one yet - but basically this is an alternative way - you either use another window in createDeviceEx OR you use SExposedVideoData, not both. So SExposedVideoData might also work (if I find time I might give that a shot), but for now not necessary.

Second - do not set IgnoreInput. I do not know yet why that fails, but as long as it's set to false OpenGL work in the window. Likely has to do with Irrlicht not using the Window directly in that case, but creating a child-window inside of it ... which I suppose has some different parameter which works with OpenGL for some reason.

Edit: I suppose it's because the child window uses the values from CGLXManager about the visual opengl needs.
So basically the original window has no visual which works with OpenGL (visual describes what the Window supports and OpenGL has to be specifically requested). Which also means using that one with SExposedVideoData is unlikely to work.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Post Reply