What about input system improvements ?

Discuss about anything related to the Irrlicht Engine, or read announcements about any significant features or usage changes.
Post Reply
teto
Posts: 159
Joined: Thu Dec 03, 2009 9:37 pm
Location: /home
Contact:

What about input system improvements ?

Post by teto »

Hi there,

am sure that 80% of us rewrite the same code to know if a key is pressed or not (for example keeping a table of booleans called Buttons set to true on PressedDown events,false otherwise) and to compute useful joystick-related events.

Among the few things I find annoying:
-Impossibility to retrieve state of a key
-Joystick events are inconsistants with mouse & keyboard handling, they are not events but states in fact

That's why I've started developing a proof of concept for windows API only just to know if devs were interested by these "improvements" (in my opinion). This is inspired by SFML (http://www.sfml-dev.org) and OIS as well.

Here is a summary of functions I've quickly implemented for the windows32 API (The main difference with current code is the creation of an IJoystick* class):

Code: Select all

 
bool IrrlichtDevice::isJoytickConnected(id)
IJoystick* IrrlichtDevice::getJoystick(u8 const& id)
bool IrrlichtDevice::getJoysticks( array<IJoystick*> )
 
CMouse::isButtonPressed(button)
CKeyboard::isKeyPressed(key)
 
 
IJoystick::isButtonPressed(button)
IJoystick::getAxisValue(axis)
IJoystick::hasAxis(axis)
bool IJoystick::hasPOV()
IJoystick::getPOV()
 
 
 
// if we generate events for axis we could use 
[ IJoystick::setThreshold ]
 
 
// different types of event
    enum EJOYSTICK_EVENT {
        EJE_PLUGGED,
        EJE_UNPLUGGED,
        EJE_BUTTON_PRESSED,
        EJE_BUTTON_RELEASED,
        EJE_POV_MOVED,
        EJE_AXIS_MOVED
 
    };
 
 
// asks for a new SJoystickEvent
        struct SJoystickEvent
        {
        EJOYSTICK_EVENT Type;
        u8 Id;  //joystick id (or pass IJoystick*)
 
        EJOYSTICK_AXIS     MovedAxis;
 
        // could use a union here
        u8  Button;  // Index of pressed button
        s16 Axis;
        u16 POV;
}
 
If that's the case, I am ready to write a proper patch following irrlicht conventions (and what comes along,doxygen comments,tutorials, for as many platforms as I can but I may need some help for exotic platforms) with a design that would be discussed over a mailing-list. Indeed there would be many points to be discussed.

For example:
-Right now, I delete unplugged IJoystick* and reallocate them when plugged. Maybe we could just change a boolean "Connected"
-How to handle IJoystick instances, with a reference counter ?
-should we generate plug/unplug events if joysticks are not activated with activeJoystick ?
-how often should we check joystick state ? each frame ? each 30ms ?
-concerns about design implementation, which function goes where, do we place enums in namespace/class etc...

I am willing to adapt directInput (it looks deprecated in favor of XInput which has some defects too, maybe rely on winapi only ? what are the advantages of Direct Input ?).

Tell me if you are interested and if yes how do you want me to proceed, patch per platform, what tests you want me to write etc...

That's also sthg to discuss if there is any interest. Keep in mind the current code is just to get some feedback and start a discussion and does not reflect a final one.
I think my improving this part of irrlicht shouldn't be a burden for current dev.In fact input code is a code part that once finished shouldn't evolve much.

Btw the patch is downloadable here (built against rev3905 / irrlicht1.8)
This is currently for WIN32 api ONLY and applying the patch on windows might be tricky. You should install patch.exe for windows and then transform line endings into CR+LF format (with notepad++ for instance). Then a "patch -p0 -i improvedInputForWin32api.patch" from trunk folder should do the trick. I know you are looking for developers that would help you solving bugs. That's something I might do in the future but this one has been in my bonnet for quite some time.

Here is a small main.cpp to test features.

Code: Select all

 
#include <irrlicht.h>
#include <iostream>
 
using namespace irr;
 
 
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
 
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
 
class MyEventReciever : public IEventReceiver
{
 
    bool OnEvent(const SEvent& event){
 
        if(event.EventType != EET_JOYSTICK_INPUT_EVENT){
            return false;
        }
 
        char logString[256] = "no message";
//            (void)sprintf(logString, "Found joystick %d,  %d buttons '%s'",
//                joystickId,
//                caps.ButtonCount,
//                "unknown");
 
 
        switch(event.JoystickEvent.Type){
 
            case EJE_PLUGGED:
                sprintf(logString,"Joystick %d plugged",event.JoystickEvent.Id);break;
 
            case EJE_UNPLUGGED:
                sprintf(logString,"Joystick %d unplugged",event.JoystickEvent.Id);break;
 
            case EJE_BUTTON_PRESSED:
                sprintf(logString,"Button %d of Joystick %d pressed",event.JoystickEvent.Button,event.JoystickEvent.Id);break;
 
            case EJE_BUTTON_RELEASED:
                sprintf(logString,"Button %d of Joystick %d released",event.JoystickEvent.Button,event.JoystickEvent.Id);break;
 
            case EJE_POV_MOVED:
                sprintf(logString,"Pov moved");break;
            case EJE_AXIS_MOVED:
                sprintf(logString,"Axis %d moved. New value:",event.JoystickEvent.MovedAxis);break;
            default:
                break;
 
        };
 
        std::cout << logString << std::endl;
        return false;
 
    };
 
 
};
 
/*
This is the main method. We can now use main() on every platform.
*/
int main()
{
 
        IrrlichtDevice *device =
                createDevice( video::EDT_SOFTWARE, dimension2d<u32>(640, 480), 16,
                        false, false, false, 0);
 
        if (!device)
                return 1;
 
        device->setWindowCaption(L"Hello World! - Improved Input Demo");
 
    MyEventReciever myReceiver;
    device->setEventReceiver( &myReceiver );
 
        IVideoDriver* driver = device->getVideoDriver();
        ISceneManager* smgr = device->getSceneManager();
        IGUIEnvironment* guienv = device->getGUIEnvironment();
    ILogger* logger = device->getLogger();
    IJoystick* joystick0 = 0;
 
        guienv->addStaticText(L"Hello World! This is the Irrlicht Software renderer!",
                rect<s32>(10,10,260,22), true);
 
 
        smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0));
 
    // Kept cos it's just a proof of concept. Serve no purpose
    core::array<SJoystickInfo> joystickInfo;
 
    //device->activateJoysticks(joystickInfo);
 
    if( device->activateJoysticks(joystickInfo) ){
 
        logger->log("Joysticks enabled");
    }
    else {
        logger->log("No joystick detected",ELL_ERROR);
        return 0;
    }
 
 
 
    core::array<IJoystick*> Joysticks;
    int res = device->getJoysticks(Joysticks);
    std::cout << "Nb of Joysticks registered: " << Joysticks.size();
    //int res = device->getJoysticks(Joysticks);
    joystick0 =  device->getJoystick(0);
    if(!joystick0){
        logger->log("No joystick retrieved",ELL_ERROR);
        return 0;
    }
    else {
        logger->log("At least one joystick retrieved");
        joystick0 = Joysticks[0];
    }
 
 
    //sprintf()
    SJoystickCapabilities caps = joystick0->getCapabilities();
                char logString[256];
                (void)sprintf(logString, "Found joystick %d,  %d buttons '%s'",
                        0,
                        caps.ButtonCount,
                        joystick0->Name.c_str()
                        );
 
    logger->log(logString);
 
        while(device->run())
        {
 
//        if(irr::CKeyboard::isKeyPressed(irr::KEY_KEY_A)){
//            logger->log("A is pressed");
//        }
//        else {
//            logger->log("A not pressed");
//        }
 
//        if( joystick0->isButtonPressed(0) || joystick0->isButtonPressed(1)){
//            logger->log("Button 0 pressed");
//        }
//        else {
//            logger->log("Button 0 not pressed");
//        }
 
 
                driver->beginScene(true, true, SColor(255,100,101,140));
 
 
                smgr->drawAll();
                guienv->drawAll();
 
                driver->endScene();
        }
 
        device->drop();
 
        return 0;
}
 
/*
That's it. Compile and run.
**/
 
Last edited by teto on Fri Sep 02, 2011 8:24 am, edited 1 time in total.
Using trunk with mingw/gcc 4.6, Windows 7 64 bits driver opengl
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Re: What about input system improvements ?

Post by hybrid »

Yes, I'm also planning to add some more structure around the joystick handling. Basically because I want to add force feedback. Don't know if mouse and keyboard is really necessary. After all we are using an event system. Though having a clean interface and generalizing the input handling might be quite nice. So well, just give some input. Might save me some time.
Oh, and joystick interfaces are really complicated. There's no really deprecated API under Windows. None of the new APIs covered all of the previous one. So there's good chance to find problems which can only be solved by one of the APIs. So the more the better. But of course focusing on just one API first is ok.
3DModelerMan
Posts: 1691
Joined: Sun May 18, 2008 9:42 pm

Re: What about input system improvements ?

Post by 3DModelerMan »

Yes that sounds like a great idea. I like the get joystick method. It's like XNA's input kinda.
That would be illogical captain...

My first full game:
http://www.kongregate.com/games/3DModel ... tor#tipjar
teto
Posts: 159
Joined: Thu Dec 03, 2009 9:37 pm
Location: /home
Contact:

Re: What about input system improvements ?

Post by teto »

Yes, I'm also planning to add some more structure around the joystick handling. Basically because I want to add force feedback.
Don't know if mouse and keyboard is really necessary.
Those are just 2 functions and at least on windows it's very simple. (a simple conversion from irrlicht enums to windows ones and then returns getAsyncKey(key) (same for mouse). On other platforms, we could maintain a table updated from events. At least for keyboard, it's nice to know if a key is pressed to keep strafing for example. It's not because it's simple but because it's useful I would add it. I agree the feature is less interesting for the mouse.
After all we are using an event system. Though having a clean interface and generalizing the input handling might be quite nice. So well, just give some input. Might save me some time.
The more precisions I get, the less work you'll have to do in the end. I want to provide a patch you could apply without much modification. That's why I need to ask you devs about the design and how to work. I can provide a clean patch for windows. If you are ok with the design, I provide a patch for linux too etc... ? Subversion doesn't make it easier though. Are there any plans to move to git or something more modern (plz don't take on that troll :p) ?
Maybe this discussion would be more appropriate over a mailing list or over mail. you can mail me at "mattator at gmail dot com"
Oh, and joystick interfaces are really complicated. There's no really deprecated API under Windows. None of the new APIs covered all of the previous one.
From what I read,XInput handles Xbox controllers but not the other ones. So this
I have yet to find the advantages of DirectInput compared to winApi.
So there's good chance to find problems which can only be solved by one of the APIs. So the more the better. But of course focusing on just one API first is ok.
well if you change one, you need to change others otherwise it won't compile anymore.
Yes that sounds like a great idea. I like the get joystick method. It's like XNA's input kinda.
Don't know about XNA's input even though I have been willing to try XNA for years :p
Using trunk with mingw/gcc 4.6, Windows 7 64 bits driver opengl
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Re: What about input system improvements ?

Post by hybrid »

teto wrote: The more precisions I get, the less work you'll have to do in the end. I want to provide a patch you could apply without much modification. That's why I need to ask you devs about the design and how to work. I can provide a clean patch for windows. If you are ok with the design, I provide a patch for linux too etc... ? Subversion doesn't make it easier though. Are there any plans to move to git or something more modern (plz don't take on that troll :p) ?
Maybe this discussion would be more appropriate over a mailing list or over mail. you can mail me at "mattator at gmail dot com"
My idea is to have just one API method in the device which return the Joystick array (or an input handler, assuming that more than jysticks is in there, this would result in another layer, which is queried for the joysticks then). The methods should mimik the current organization of values and signals. Usually, we try to group similar components in one method, and pass the distinction parameter (an enum value). Whether the isConnected is necessary or can be recognized via the nullptr return from getJoystick() is a matter of taste. I guess we can discuss such minor things later on.
Patch is a good idea, git not. IMHO, git is the best tool if you want to make easy things complicated. And of course it's also good to perform complex things complicated. But not much more. So for now you either have to sync with your local git repository if you really need it.
And no, discussion should be kept open and in the forum.
teto
Posts: 159
Joined: Thu Dec 03, 2009 9:37 pm
Location: /home
Contact:

Re: What about input system improvements ?

Post by teto »

I will go for an IInputHandler since that's what leaves most options open and it would be easier to move its member functions to other classes than the other way around. (+ it's nearly the same as CJoyControl for example).

I will try to have something ready for both linux & winApi by the end of next week (maybe macOS though I can't test :/). I am not sure what to do with directinput.

As for svn/git, it was a silly recommendation. I will save changes by doing several patches for myself, that's all ;)
Using trunk with mingw/gcc 4.6, Windows 7 64 bits driver opengl
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Re: What about input system improvements ?

Post by hybrid »

DirectInput is already implemented in Irrlicht. It's enabled or disabled via compile time flag. I'd keep this as is.
teto
Posts: 159
Joined: Thu Dec 03, 2009 9:37 pm
Location: /home
Contact:

Re: What about input system improvements ?

Post by teto »

Here is a new patch for DirectInput/Win32 and linux. It's not thoroughly tested yet nor cleaned (commented code) but it's a good base to discuss & start with. I've compiled it successfully for those platforms though I could not run my exemple (program starts but screen remains blank, I suspect a bug somewhere but I lost patience with gdb).
I have not tried compiling without defining _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ .


Here are a few dilemns I'm confronted with:
-I use a unique structure called SJoystickCapabilities to register joystick capabilities. To get a joystick capabilities, we need to call IJoystick::getCapabilities().ButtonCount / hasAxis / hasPOV etc... Maybe that would be best to have virtual functions in IJoystick such as hasAxis/hasPov. Dunno.
-the way to retrieve joystick. I have 3 possibilities in mind:
--calling activeJoystick(array<u8>) where we stock indices of valid joystick into array
--calling activeJoystick(array<IJoystick*>), we directly stock joystick
--calling int activeJoystick() which returns number of vali joystick. Each discovered joystick generates a EJE_INIT (could the same as EJE_PLUGGED) event sent to event reciever.
-in SJoystickEvent, same problem, I don't know if it's better to pass joystick or to pass an ID. In the first case, I don't need any getJoystick(u8) method.

-I think we should set a global limit to supported number of joysticks (that's what already happens for linux)


On my roadmap:
- I would like to unify POV between windows & linux (which has 2 axes POVX & POVY)
- add functions such as isKeyPressed,isMouseButtonDown
- unplugging a joystick will make the exemple crash because it doesn't remove it from the GUI list. I will correct that

While working on this project, I noticed a few bugs in CodeBlocks project (about targets names, .obj folders) + this error while compiling fast math if I remember:

Code: Select all

 
...
Compiling: zlib/zutil.c
Linking dynamic library: ../../lib/Linux/libIrrlicht.so
/usr/bin/ld: ../obj/linux-gcc-release-fast-shared/C3DSMeshFileLoader.o: relocation R_X86_64_32S against `vtable for irr::core::irrAllocator<char>' can not be used when making a shared object; recompile with -fPIC
../obj/linux-gcc-release-fast-shared/C3DSMeshFileLoader.o: could not read symbols: Bad value
collect2: ld returned 1 exit status
Process terminated with status 1 (4 minutes, 55 seconds)
0 errors, 21 warnings (4 minutes, 55 seconds)
I've added a "-d" suffix to debug to the codeblocks project. Would there be interest if I create a CMakeFile ? Maybe there is already one ? that would generate coherent projects.


I noticed that documentation for push_front (of core::array) is the same as for push_back.

@Hybrid> I have not a force feedback joystick but I was surprised that Linux somehow supported it, if you are interested: http://freegamedev.net/wiki/Force_Feedback

Screen of current demo. Not very sexy yet but we can choose joystick/threshold and see buttons/axes values.
Image

Current patch: http://downloads.tuxfamily.org/bluecosm ... 2011.patch
Exemple: http://downloads.tuxfamily.org/bluecosm ... deMatt.zip
Using trunk with mingw/gcc 4.6, Windows 7 64 bits driver opengl
teto
Posts: 159
Joined: Thu Dec 03, 2009 9:37 pm
Location: /home
Contact:

Re: What about input system improvements ?

Post by teto »

Now working on linux and windows (though I have a problem with DirectInput not acquiring my joystick, Win32 APi works fine).

-removed the SJoystickCapabilities structure, function hasPovHat(), getButtonCount(), isAxisSupported() are now virtual.
-Linux checks for new joysticks on a periodic basis (every 5 sec).
-Unified povhat values through an enum:

Code: Select all

enum E_JOYSTICK_POVHAT_VALUE
{
EJP_CENTERED,
EJP_NORTH,
EJP_NORTH_WEST,
EJP_WEST,
EJP_SOUTH_WEST,
EJP_SOUTH,
EJP_SOUTH_EAST,
EJP_EAST,
EJP_NORTH_EAST
};
-unified axes values. Whatever your joystick on your platform, axes' values are between -1.f and 1.f which allows an uniform way ...
- ... an uniform way of setting threshold values (prevents from generating EJE_AXIS_MOVED if axis move too small). Per-Joystick threshold implemented.
- ... for setting deadzones. I've seen that my Pad doesn't always go back to 0.f but rather to 0.03f (same behavior before uniformizing axes values). Per-axis deadzone implemented. Maybe it adds too much overhead and I should do a global deadzone ?


/!\ My main question would be right now : is there any mac developer who wants to help me port that on Mac ?

That's very easy, there are two classes to inherit from: IInputManager and IJoystick. Then it's copy & paste of current system support with a few modifications to detect plugged joysticks and fill a SJoystickState structure. Events are then automatically generated ( by compareason with last frame state).

Nb: I will provide binaries when I get to solve the directInput pb.
Using trunk with mingw/gcc 4.6, Windows 7 64 bits driver opengl
Post Reply