Irrlicht + wxWidgets + Linux (updated 04 October 2010)

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
cheshirekow
Posts: 105
Joined: Mon Jul 27, 2009 4:06 pm
Location: Cambridge, MA

Irrlicht + wxWidgets + Linux (updated 04 October 2010)

Post by cheshirekow »

Update 04 October 2010: new sources

Irrlicht plays well with wxWidgets on windows, as one can just get a handle to the window you want to render in, and pass that pointer to the createDeviceEx() function. On linux, it's a little harder. So there's two ways to do this. The easy way, and the right way.

Disclaimer

The information presented here is my understanding based on information I received from the internet. Therefore it is absolutely and 100% true. If you believe there to be an error, take it up with the internet (or just post a reply).

Introduction

First of all, it's helpful to understand how Irrlicht and WxWidgets are different. In the beginning, there was hardware (graphics hardware to be precise). Then there's the X Windows System, which is a pretty thin abstraction of the hardware. X manages a tree in memory of "windows" which are logical rectangles that can be drawn on, and that it can render to the physical screen. X does not manage gui controls and, in fact, doesn't really deal with the details of the appearance at all. The window manager (Gnome, or Compiz in standard ubuntu) actually handles how to draw the windows. GTK+ is a gui widget/control/thingamajig/library that is implemented by the window manager and sits on top of X and provides all of the details for drawing pretty gui controls. WxWidgets is a gui widget/control/thingamajig/library that sits on top of GTK+ (at least in the case of linux) and provides a nice object oriented, c++ API for creating gui's.

Now, 3d drawing (as far as irrlicht is concerned) is done through opengl. OpenGL is a library for drawing stuff (typically implemented in a hardware specific way). OpenGL plays nice with the other kids on your Linux screen real-estate through X. Irrlicht sits on top of openGL and provides a nice c++ API for creating scenes.

ASCII-Graphically, we have this:

Code: Select all

     ___________________
    |     wxwidgets     |     _______________ 
    |  _______________  |    |    irrlicht   |
    | |     gtk       | |    |  ___________  |
    | |  ___________  | |    | |  opengl   | |
    | | |   gnome   | | |    | |  _______  | |
    | | |  _______  | | |    | | |       | | |
    | | | |       | | | |    | | | nativ | | |
    | | | |   X   | | | |    | | |_______| | |
    | | | |_______| | | |    | |_____|_____| |
    | | |_____|_____| | |    |_______|_______|
    | |_______|_______| |            |
    |_________|_________|            |
              |        __________    |      
              |      |          |    |       
              ------>| hardware |<----
                     |__________|
So you see how it might be hard to do what we want. As it turns out Irrlicht draws to the screen using X, so in order to get wxWidgets and Irrlicht to play together, we have to dig through a few of the APIs to get what we need.

The easy way (see sources a few posts below):

The constructor for a CIrrDeviceLinux will accept as a SIrrlichtCreationParameters::WindowId the numeric id of an XWindow. It will assume that the window is on the local X server (device 0), and it will attempt to create a glx window from that one. Therefore, all we need to do, is get the X window id. So what we do is we derive a class from wxGLCanvas, and put one of these in a wxWidgets window. At some point after that object has been displayed, we use GetHandle() on our object. The result, on wxGTK is a GTKWidget* pointer. The GTKWidget struct contains a member called "window" which is a pointer to something else. We can then use the GDK_WINDOW_XDISPLAY() macro to get the window id of the X Window of the GTKWidget of the wxWidget (*whew*). If you're curious where the "GDK" came from, GTK is actually built on top of another library called GDK, but I was already tired of making the ASCII art diagram so I left it out until now.

In any case, once we have that ID we can stuff it into a SIrrlichtCreationParameters object and pass it into the createDeviceEx() function to create our irrlicht device. Then, the onPaint handler for our widget does the following:

1. Set it's GL context to the active one
2. Tell irrlicht to render the scene
3. Swap it's buffers to make the new image visible

Now there's a little bit of a thing here. As it turns out, the wxGLCanvas actually makes it's own glxContext object, so things go a little screwy in the CIrrLinuxDevice constructor. As a result, you'll see a little bit of gibberish spit out on your console:

Code: Select all

X Error: BadMatch (invalid parameter attributes)
From call : unknown
X Error: GLXBadDrawable
From call : unknown
Could not make context current.
Nevertheless, it seems to work, so I guess Irrlicht manages to get it figured out later on. I haven't dug further into the source to see why. In any case, here's the source for the wxWiget along with some test code (edit: removed, see post below)

The Right Way (updated 04 October 2010)

The reason it works with a wxGLCanvas is that the Irrlicht OpenGL driver class queries XLib and GLX libraries to get the "current" Drawable (window) and GL Context. Therefore, even though the Irrlicht Device constructor thinks it failed to create these things, since the wxGLCanvas already made them current, the OpenGL driver can still find them when it is initializing.

The truth is that we don't actually need a wxGLCanvas to attach irrlicht to a wxWidgets window though. If we try to pass in a normal wxWindow's XWindow id, however, we get errors and nothing is displayed. This is because wxWidgets creates an XWindow whose attributes do not match those that are implied by the parameters of SIrrlichtCreationParameters. So, we have two options.
  1. Figure out the attributes of the XWindow that wxWidgets has created, map those to the appropriate values of the elements in SIrrlichtCreationParameters, and pass those in when we create the irrlicht device
  2. When Irrlicht creates a new device, just create a new XWindow as a child of the one that is passed in.
The first wont require modification of the Irrlicht sources, but is essentially impossible to do in a portable way. The second is the approach I have embraced. As a side effect, since irrlicht has it's own XWindow it's pretty easy to ensure that all of the X resources are owned only by the irrlicht device. Consequently, it's possible to run irrlicht in it's own thread! My updated source code demonstrates how to render on a timer in the GUI thread (the easiest way), asynchronously in a separate thread (the GUI signals a render to start, but does not block while the rendering is done), or continuously in another thread (the GUI thread starts the rendering, but lets it run unmonitored afterward, like a movie).
Last edited by cheshirekow on Mon Oct 04, 2010 11:22 pm, edited 5 times in total.
cheshirekow
Posts: 105
Joined: Mon Jul 27, 2009 4:06 pm
Location: Cambridge, MA

Post by cheshirekow »

Obligatory Screenshot. Ubuntu 10.04 AMD64

Image

Uploaded with ImageShack.us
sudi
Posts: 1686
Joined: Fri Aug 26, 2005 8:38 pm

Post by sudi »

i can't seem to download the file...ideas?
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
cheshirekow
Posts: 105
Joined: Mon Jul 27, 2009 4:06 pm
Location: Cambridge, MA

Post by cheshirekow »

Hey Sud, I'm not sure. It's probably just that stupid website. I'm working on updating the patch so I'll post again in a few days and just post the source directly.

Right now, I'm skeptical that it's even necessary to alter the source. The reason is that those errors that are seen when using the released source appear to be part of trying to poll the capabilities of the system. If I'm correct, all of the work that is done when those messages are generated is ignored if you set IgnoreInput to true anyway, and then passing in creation parameters is meaningless because the context is already created, so the setup will have to be done in the wxGLCanvas constructor. I'll post more details in a few days when I understand a bit more.
sudi
Posts: 1686
Joined: Fri Aug 26, 2005 8:38 pm

Post by sudi »

ok looking forward to it. this would actually allow me to run EditIrr on linux which would be awesome bc then we have an editor even for linux :D
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
cheshirekow
Posts: 105
Joined: Mon Jul 27, 2009 4:06 pm
Location: Cambridge, MA

Post by cheshirekow »

Updated version, does not require patched sources. Save these file in a directory like this

Code: Select all

wxIrrlicht
 |-- Makefile
 |-- wxIrrlichtCanvas.cpp
 |-- wxIrrlichtCanvas.h
 |-- test
 |    |-- wxIrrlichtTest.cpp
 |    |-- sydney.md2
 |    |-- sydney.bmp
The model and texture files "sydney.md2" and "sydney.bmp" can be found from the irrlicht source archive or svn repository. They're in the "media/" directory of the archive root.

Image

Using the demo. The app creates a mesh node and a FPS camera node. The FPS controls (up/down/right/left) will work when the window has focus. The mouse controls (looking around) will only work while you're clicking and dragging the area. When you release the mouse will be free to move around again. The mouse is not hidden while you're using the camera. Not all of the keys or button presses are mapped and send to irrlicht, but you can see from the example how to do it.

Issues:
  • You'll see the terminal complain about "Bad Drawable" and some other things when the program initializes. This is ok.
  • Also, do not try to resize the window. There is no way to inform the irrlicht device the window size is changing, except my manually putting X events onto the stack before calling device->run(). You can tell the driver with onResize() but then it will stretch it onto the actual window. So for now, just don't resize the window. I'll be updating later with a patch to the engine that I'm using for this. Or you can just use Xlib to put events on the stack. (note: updated to fix this)
  • There's a segmentation fault when you close the program. I'm not sure if the device is getting destroyed twice or the failure during initalization is leaving a null pointer somewhere. If it really bothers you, uncomment the call to destroyDevice() and just let it get cleaned up when main() exits. I don't have this problem in my expanded version of this class so I'll try to confirm that it is in fact the initialization failure (in which case my patch will be the appropriate fix)
Compile (on linux) with "make" and then run test/wxIrrlichtTest to see the test.

Corrections and things are welcome, but will be slowly addressed.

Edits:
  • Added a source patch to allow wxwidgets to tell irrlicht the window size is changing, the patch is at the bottom. Save as windowevents.diff in the root directory of the source archive, and apply with "patch -p0 -i windowevents.diff"
  • Tarred the sources and put on http server
Sources: easyWxIrrlicht.tar.gz
Last edited by cheshirekow on Mon Oct 04, 2010 11:28 pm, edited 2 times in total.
Midnight
Posts: 1772
Joined: Fri Jul 02, 2004 2:37 pm
Location: Wonderland

Post by Midnight »

cheshirekow wrote:The information presented here is my understanding based on information I received from the internet. Therefore it is absolutely and 100% true.
rofl soi soi soi!
netpipe
Posts: 669
Joined: Fri Jun 06, 2008 12:50 pm
Location: Edmonton, Alberta, Canada
Contact:

Post by netpipe »

http://www.xup.in/dl,16462131/wxIrrlicht.7z/

duno why it wont compile but hopefully someone has better luck
Live long and phosphor!
-- https://github.com/netpipe/Luna Game Engine Status 95%
cheshirekow
Posts: 105
Joined: Mon Jul 27, 2009 4:06 pm
Location: Cambridge, MA

Post by cheshirekow »

What is the compiler output tecan, and what is that you linked to?
cheshirekow
Posts: 105
Joined: Mon Jul 27, 2009 4:06 pm
Location: Cambridge, MA

Post by cheshirekow »

Updated with new version. See original post for details. Sources Here
netpipe
Posts: 669
Joined: Fri Jun 06, 2008 12:50 pm
Location: Edmonton, Alberta, Canada
Contact:

Post by netpipe »

not sure who posted this previously, but i updated my os and the new wx seems to work with older versions of irrlicht. here's it is http://tecan.ath.cx/irrlicht/wxWorkingIrrlicht.7z
Live long and phosphor!
-- https://github.com/netpipe/Luna Game Engine Status 95%
randomMesh
Posts: 1186
Joined: Fri Dec 29, 2006 12:04 am

Post by randomMesh »

I successfully compiled the example but it only runs if i use -O0 as optimization flag for g++. Other flags like -O3 will crash the demo.

gdb says:

Code: Select all

[Thread debugging using libthread_db enabled]

Program received signal SIGSEGV, Segmentation fault.
0xb7577f1f in std::_Rb_tree_decrement(std::_Rb_tree_node_base*) () from /usr/lib/libstdc++.so.6
(gdb) where
#0  0xb7577f1f in std::_Rb_tree_decrement(std::_Rb_tree_node_base*) () from /usr/lib/libstdc++.so.6
#1  0x0806697c in operator-- (this=0x8789abc, __v=...) at /usr/include/c++/4.4/bits/stl_tree.h:199
#2  std::_Rb_tree<int, std::pair<int const, irr::EKEY_CODE>, std::_Select1st<std::pair<int const, irr::EKEY_CODE> >, std::less<int>, std::allocator<std::pair<int const, irr::EKEY_CODE> > >::_M_insert_unique (this=0x8789abc, __v=...) at /usr/include/c++/4.4/bits/stl_tree.h:1179
#3  0x08066bb8 in std::_Rb_tree<int, std::pair<int const, irr::EKEY_CODE>, std::_Select1st<std::pair<int const, irr::EKEY_CODE> >, std::less<int>, std::allocator<std::pair<int const, irr::EKEY_CODE> > >::_M_insert_unique_ (this=0x8789abc, __position=..., __v=...)
    at /usr/include/c++/4.4/bits/stl_tree.h:1217
#4  0x08061c80 in insert () at /usr/include/c++/4.4/bits/stl_map.h:540
#5  operator[] () at /usr/include/c++/4.4/bits/stl_map.h:450
#6  wxIrrlichtCanvas::classInit () at ../source/wxIrrlichtCanvas.cpp:572
#7  0x08667a4d in __do_global_ctors_aux ()
#8  0x0805b9fc in _init ()
#9  0x086679e9 in __libc_csu_init ()
#10 0xb737ac85 in __libc_start_main (main=0x8068019 <main(int, char**)>, argc=1, ubp_av=0xbffff444, init=0x86679d0 <__libc_csu_init>, 
    fini=0x86679c0 <__libc_csu_fini>, rtld_fini=0xb7ff0ac0 <_dl_fini>, stack_end=0xbffff43c) at libc-start.c:185
#11 0x08061411 in _start ()
I am using the latest svn trunk of both wxWidgets and Irrlicht and g++ 4.4.5

Anyone got an idea what's wrong?
"Whoops..."
Virion
Competition winner
Posts: 2148
Joined: Mon Dec 18, 2006 5:04 am

Re: Irrlicht + wxWidgets + Linux (updated 04 October 2010)

Post by Virion »

i can't download the file. anyone still keep this? :cry:
byllgrim
Posts: 9
Joined: Mon May 28, 2012 12:13 pm

Re: Irrlicht + wxWidgets + Linux (updated 04 October 2010)

Post by byllgrim »

im not sure if either irrlicht or wxwidgets got updated and this got fixed or if im an ignorant noob overlooking something, but cant one just do this?
param.WindowId = (void*)wxTheApp->GetTopWindow()->GetHandle();
it works for me
sgqfpu
Posts: 11
Joined: Mon Apr 28, 2014 1:50 pm
Location: Taiwan

Re: Irrlicht + wxWidgets + Linux (updated 04 October 2010)

Post by sgqfpu »

byllgrim wrote:im not sure if either irrlicht or wxwidgets got updated and this got fixed or if im an ignorant noob overlooking something, but cant one just do this?
param.WindowId = (void*)wxTheApp->GetTopWindow()->GetHandle();
it works for me
I did similar, but it didn't work. The function createDeviceEx did return a non-NULL, and everything went as expected, except nothing was shown on the window. I don't know where I went wrong. It would be highly appreciated if you kindly could post your entire example here.
Post Reply