Use SDL input in Linux with Irrlicht

A forum to store posts deemed exceptionally wise and useful
Post Reply
sparkplug
Posts: 3
Joined: Thu Oct 11, 2007 4:12 pm
Location: Ursa Minor Beta

Use SDL input in Linux with Irrlicht

Post by sparkplug »

After quite a while of not being able to use SDL for input like I wanted to with the Irrlicht engine, I hit upon this topic:

http://irrlicht.sourceforge.net/phpBB2/ ... hp?t=19048

Which provided most of what I needed to get started. So I decided to write up what I did so that I would remember for next time, and possibly to help other people out a little. I've only tested this for keyboard input, obviously SDL is a whole other can of worms I don't want to go into right now, but it should provide what you need to at least use input from sources like joysticks that Irrlicht has trouble with. Anyway, this involves compiling Irrlicht with the built-in SDL option enabled, and a little bit of other finicky stuff which I'll explain. This is the first time I've ever written something like this, so please feel free to ridicule and flame me over and over again.

Download Irrlicht with this command:

Code: Select all

svn co https://irrlicht.svn.sourceforge.net/svnroot/irrlicht/branches/releases/1.4 irrlicht
Or download the trunk version like this:

Code: Select all

svn co https://irrlicht.svn.sourceforge.net/svnroot/irrlicht/trunk irrlicht
I used revision 1069 of the 1.4 release branch, but newer versions will probably work too.

Then open "irrlicht/source/Irrlicht/Makefile" in your favorite text editor, and find the line that says:

Code: Select all

CPPFLAGS = $(CXXINCS) -DIRRLICHT_EXPORTS=1
That is line 51 in the revision 1069 version of the Makefile, and may be in future versions too. Anyway, add -D_IRR_USE_SDL_DEVICE_ to that line. It may vary in future revisions of Irrlicht, but for revision 1069 that line should now read:

Code: Select all

CPPFLAGS = $(CXXINCS) -DIRRLICHT_EXPORTS=1 -D_IRR_USE_SDL_DEVICE_
The important thing there is that you add the -D_IRR_USE_SDL_DEVICE_ to the CPPFLAGS.

Before you can compile you need to add a few lines of code to another file. At the very beginning of "irrlicht/source/Irrlicht/COpenGLExtensionHandler.cpp", add these three lines of code:

Code: Select all

#ifdef _IRR_USE_SDL_DEVICE_
#include <SDL/SDL_video.h>
#endif

Now compile Irrlict from scratch, probably like this:

Code: Select all

make NDEBUG=1

That should produce a working copy of Irrlicht compiled to automatically use SDL. A few things are different in Irrlicht with the SDL version, possibly some bugs, although I don't really know. For starters, the mouse cursor is no longer trapped inside the window. This is relatively minor for me, since I usually leave the mouse cursor visible anyway. There is a larger problem which I'm not really sure about however, and that is the fact that Irrlicht thinks its rendering window is inactive until the mouse cursor gets placed on top of it. To avoid this, I stopped checking if the window was active before rendering. It works, but might not in all situations. I think it might be a bad idea, but I'll use that method anyway for now because it seems to work.

To compile programs for SDL/Irrlicht you will need to include the SDL library and header directories. To do that you'll have to add this to either the CPPFLAGS in your makefile, or if you compile your source code by hand with g++, just add it to the g++ command:

Code: Select all

-I/usr/include/SDL -lSDL

The only thing I've tried like this so far is a simple implementation of SDL input in the Quake 3 Map sample program, which I compressed and uploaded just in case you want to take a look at it.

Quake3MapChanges.zip
There is a 90% chance of potatoes today.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Why do you need the SDL_video in COpenGLExtensionHandler? I did not need it. SDL_opengl.h gets included, which should be enough?!
I did not yet continue with SDL stuff, so feel free to give any input on enhancing the device features. For example mapping SDL input to Irrlicht events could be improved, also the window states. However, the behavior of being disabled until clicked is due to your current window manager, and also happens with the Linux device in many cases. So it's an intended feature :)
sparkplug
Posts: 3
Joined: Thu Oct 11, 2007 4:12 pm
Location: Ursa Minor Beta

Post by sparkplug »

I thought adding SDL_Video.h to COpenGLExtensionHandler might be unnecessary, so I tried compiling it from a few different revisions without that, and it never worked. So I guess if it does work out for people without adding that line, great. But I doubt adding it causes any problems and it was the only way to get it to compile for me, and maybe some other people as well.

And yeah I thought my window manager might be at fault there, but it wouldn't be all bad if there was a function to set the Irrlicht window to be active, sort of like the RenderWindow::setActive(bool) function in Ogre. The window managers do tend to be a little on the buggy side though, so it could be a bad idea or impossible, I don't know.

I don't really care about mapping the SDL inputs to Irrlicht events, since I use the SDL event handler anyway, but maybe the SDL_QUIT event would be a good one to have integrated.

EDIT: OK, I looked into the SDL_video.h thing, and when I compile without it I get this error:

Code: Select all

COpenGLExtensionHandler.cpp:196: error: ‘SDL_GL_GetProcAddress’ was not declared in this scope
I looked at SDL_video.h and SDL_opengl.h, and SDL_opengl.h does not declare the SDL_GL_GetProcAddress function, while SDL_video.h does. That's probably the reason for the error.
There is a 90% chance of potatoes today.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Ok, I see. Maybe it's a version problem, I don't know which version I tried. I'll have a look at it. Thanks.
dudMaN
Posts: 111
Joined: Fri Mar 02, 2007 6:37 pm

Post by dudMaN »

Wouldnt it be simpler to ONLY use SDL's input? or just use irrlicht's default input system? it's quite good.


-dudMan
Complete Irrlicht Beginners Tutorial
http://irrlicht.sourceforge.net/phpBB2/ ... hp?t=24898
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

How'd you use only SDL input? Irrlicht needs to know about some events.
sparkplug
Posts: 3
Joined: Thu Oct 11, 2007 4:12 pm
Location: Ursa Minor Beta

Post by sparkplug »

And the built in Irrlicht input system is great for keyboard input, but SDL covers a much broader range of hardware.

EDIT: I tried using SDL on the 1.4 release (SVN 1075) that just came out and the SDL bit works just like before.
There is a 90% chance of potatoes today.
a4z
Posts: 4
Joined: Wed Feb 07, 2007 12:47 pm

Post by a4z »

hi,
nice to read that I am not the only person who has interests to use Irrlicht + SDL


my current status is that I have written a sdl2irr event forward class

so I can use/handle SDL Events and afterwards using Irrlicht Eventsystem

currently my main loop looks like that:

Code: Select all

	bool run = true ;
	SDL2IrrEvent s2i; 
	//void ForwardEvent(SDL_Event& SDL_event, irr::IrrlichtDevice* device);
	while(run)
	{
		
		SDL_Event event;
		while ( SDL_PollEvent(&event) ){
			
			if ( event.type == SDL_QUIT ) {
				run = false;
				break;
			}
			s2i.ForwardEvent( event, device );			
			// here the sdl event are translated like in CIrrDeviceSDL::run()
			// and also forwarded to Irrlicht via device->postEventFromUser(irrevent)
		}
		
		device->getTimer()->tick();
		
		driver->beginScene(true, true, SColor(255,100,101,140));

		smgr->drawAll();
		guienv->drawAll();
		driver->endScene();
	}


that solution has some disadvantages (so I don't post the code for the code SDL2IrrEvent class, it is nearly a 100% copy and past thing from CIrrDeviceSDL, if someone is interested I can post it)

following things which are handled in CIrrDeviceSDL::run() will not be handled/available with that solution

//--
I can't use while(device->run())

//--
case SDL_MOUSEMOTION:
....
MouseX = irrevent.MouseInput.X = SDL_event.motion.x;
MouseY = irrevent.MouseInput.Y = SDL_event.motion.y;

I can't set MouseX/Y

//--
case SDL_ACTIVEEVENT:
if (SDL_event.active.state == SDL_APPMOUSEFOCUS)
WindowActive = (SDL_event.active.gain==1);
...
I can't set WindowActive
//--
case SDL_QUIT must be handled ,



at the moment this is no problem for me, but it will be one soon

so I think I have to change some things in CIrrDeviceSDL and include CIrrDeviceSDL.h in my code to get what I want/need
I want/need to be able to get events, process them if I want, and then forward them to the graphic engine to have/use the engines own event system

I think that should be possible, with some limitations, eg that I will have to put CIrrDeviceSDL.h (and at least CIrrDeviceStub.h IImagePresenter.h) to the include dir (or additional including source/Irrlicht) and having one or two additional lines of code in my main loop

If someone is interested I can post the result here, but it will took a few days or even weeks, I don't know when I will find the time to do that



My preferred solution would be to have the possibility to choose between

CIrrDeviceSDL * device = createDeviceSDL(...)

IrrlichtDevice * device = createDevice(...) (without getting a sdl device)

at runtime, but realising that will be to time-consuming at the moment (for me)
CuteAlien
Admin
Posts: 9651
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

I use SDL only for joystick input. For that reason (and because compiling SDL on linux also didn't work otherwise) I build SDL myself and configure it to use only the input parts.

On linux:

Code: Select all

./configure CPPFLAGS=-O2 --prefix=$LIB_RELEASE --enable-static=no --enable-audio=no --enable-video=no --enable-cdrom=no --enable-threads=no --enable-file=no --enable-loadso=no 
On Mingw:

Code: Select all

./configure --enable-joystick --disable-static --disable-timers --disable-audio --disable-video --disable-cdrom --disable-threads --disable-file --disable-loadso --disable-directx --prefix=$LIB_RELEASE
Note that $LIB_RELEASE is just the target folder for the build.

Within the game I don't try to merge the irrlicht and SDL input systems but I use a complete own structure. All my input devices like keyboard, mouse, joystick have to fill class objects which are using that interface:

Code: Select all

enum InputDeviceType
{
    IDP_NONE,
    IDP_KEYBOARD,
    IDP_MOUSE,
    IDP_JOYSTICK,
    IDP_MAX,
};

class IInputDevice
{
public:
    IInputDevice() : mIsEnabled(true)   {};
    virtual ~IInputDevice() {}

    virtual std::string GetTypeName() const = 0;        // like mouse, keyboard, joystick 1
    virtual std::string GetDeviceName() const = 0;      // as delivered by the system
    virtual InputDeviceType GetType() const = 0;

    virtual void Update() = 0;

    // returns the max number axis supported
    virtual int GetNumAxes() const = 0;

    // returns the max number buttons supported
    virtual int GetNumButtons() const = 0;

    virtual std::string GetNameAxis(int axis_) const = 0;
    virtual std::string GetNameButton(int button_) const = 0;

    virtual bool IsAnyButtonDown(int & button_) const = 0;
    virtual float IsAnyAxisMoved(int & axis_) const = 0;    // returns the amount of moving

    virtual bool IsButtonDown(int button_) const = 0;
    virtual float GetAxisValue(int axis_) const = 0;  // between -1 and 1

    void SetEnabled(bool enabled_)      { mIsEnabled = enabled_; }
    bool IsEnabled() const              { return mIsEnabled; }

private:
    bool    mIsEnabled;
};
I have an InputDeviceManager which offers access to all that devices and has some more useful tool functions (like - wait for any axis moved in any device). From outside the InputDeviceManager I just expect all device to deliver the correct values whenever I ask them. I don't care how they handle that internally. So the irrlicht devices fill the values within the evenreceiver, while for the sdl-joystick one SDL_JoystickUpdate() is made each frame and afterwards functions like those are used:

Code: Select all

bool DeviceJoystick::IsButtonDown(int button_) const
{
    if ( !IsEnabled() )
        return false;

    return SDL_JoystickGetButton(mSdlJoystick, button_);
}
I only need one include for SDL:

Code: Select all

#include <SDL/SDL.h>
Initialization also just uses the input sytem:

Code: Select all

    SDL_Init(SDL_INIT_NOPARACHUTE);
    SDL_InitSubSystem(SDL_INIT_JOYSTICK);
But I had to take care a little because SDL seemed to want it's own main functions sometimes. It's been a while - but I think I avoided that either by some defines or maybe part of that was also that the SDL include was not allowed to be in the namespace of my main function (I think the SDL faq did deliver some hints how to handle that stuff).

Btw. - on some higher level ( a few more interfaces between ... that would get too long for here) I still did sometimes send fake events to Irrlicht to simulate keypresses by other devices. I did that as following:

Code: Select all

void SendFakeKeyEvent( irr::EKEY_CODE key_, bool pressedDown_)
{
    if ( mEnvironment ) // pointer to irrlicht gui environment
    {
        SEvent irrEvent;
        irrEvent.EventType = irr::EET_KEY_INPUT_EVENT;
        irrEvent.KeyInput.PressedDown = pressedDown_;
        irrEvent.KeyInput.Control = false;
        irrEvent.KeyInput.Shift = false;
        irrEvent.KeyInput.Char = 0; // ignore that
        irrEvent.KeyInput.Key = key_;

        mEnvironment->postEventFromUser(irrEvent);
    }
}
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