Commit 6aa1be2a authored by Robert Menzel's avatar Robert Menzel

added joystick support for QT/linux

parent 5a1cf05f
...@@ -14,7 +14,7 @@ namespace ACGL{ ...@@ -14,7 +14,7 @@ namespace ACGL{
namespace HardwareSupport{ namespace HardwareSupport{
/** /**
* NOTE: Will not work unless ACGL_COMPILE_WITH_GLFW is defined! * NOTE: Will not work unless ACGL_COMPILE_WITH_GLFW or ACGL_COMPILE_WITH_QT (linux only) is defined!
*/ */
class GamePad { class GamePad {
public: public:
...@@ -107,20 +107,32 @@ private: ...@@ -107,20 +107,32 @@ private:
int mNumberOfAxes; int mNumberOfAxes;
int mButtonMap[GAMEPAD_BUTTON_ENUM_SIZE]; int mButtonMap[GAMEPAD_BUTTON_ENUM_SIZE];
int mAxisMap[GAMEPAD_AXIS_ENUM_SIZE]; int mAxisMap[GAMEPAD_AXIS_ENUM_SIZE];
float *mAxes; unsigned char *mButtonState; // 0 = released, 1 = pressed
float *mAxesMultiplier; unsigned char *mLastButtonState;
float mMinSensitivity; float *mAxes; // -1 .. 1 per axis
float *mAxesMultiplier; // used for scaling from the used API to -1..1
float mMinSensitivity; // a minimal axis value that has to be exceeded before it is evaluated
std::string mJoystickName;
// fills mAxis and mButtonState and also stores the old state
void getAxisAndButtonValues();
// //
// GLFW specifics: replace this to support joysticks with other APIs // GLFW specifics: replace this to support joysticks with other APIs
// //
#ifdef ACGL_COMPILE_WITH_GLFW #ifdef ACGL_COMPILE_WITH_GLFW
const unsigned char *mGLFWButtons; const unsigned char *mGLFWButtons; // temp. used as GLFW needs a const array
const float *mGLFWAxes; const float *mGLFWAxes; // temp. used as GLFW needs a const array
unsigned char *mLastGLFWButtonState;
int mGLFWGamePadNumber; int mGLFWGamePadNumber;
#endif #endif
//
// Custom Linux Joystick support:
//
#ifdef ACGL_OWN_LINUX_JOYSTICK
Joystick mLinuxGamePad;
#endif
}; };
ACGL_SMARTPOINTER_TYPEDEFS(GamePad) ACGL_SMARTPOINTER_TYPEDEFS(GamePad)
......
...@@ -42,7 +42,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ...@@ -42,7 +42,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// //
// TODO: get away from QT and use native C++11 threads to minimize dependencies. // TODO: get away from QT and use native C++11 threads to minimize dependencies.
// //
#if defined(ACGL_COMPILE_WITH_QT) && defined(__linux__) && defined(ACGL_EXPERIMENTAL) #if defined(ACGL_COMPILE_WITH_QT) && defined(__linux__)
#define ACGL_OWN_LINUX_JOYSTICK #define ACGL_OWN_LINUX_JOYSTICK
#endif #endif
...@@ -60,8 +60,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ...@@ -60,8 +60,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
struct EventJoystick struct EventJoystick
{ {
int32_t time; int32_t time; // seconds till unix
int16_t value; int16_t value; // -32k .. 32k
int8_t number; int8_t number;
bool synthetic; bool synthetic;
}; };
......
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#endif #endif
#if !defined(ACGL_COMPILE_WITH_GLFW) && !defined(ACGL_OWN_LINUX_JOYSTICK)
#define ACGL_NO_GAMEPAD_SUPPORT
#endif
using namespace std; using namespace std;
using namespace ACGL; using namespace ACGL;
using namespace ACGL::Utils; using namespace ACGL::Utils;
...@@ -24,7 +28,7 @@ GamePad::GamePad( int _n ) ...@@ -24,7 +28,7 @@ GamePad::GamePad( int _n )
{ {
assert( _n != 0 ); assert( _n != 0 );
#ifndef ACGL_COMPILE_WITH_GLFW #ifdef ACGL_NO_GAMEPAD_SUPPORT
assert( 0 && "compiled without any gamepad supporting library, gamepad will always report that no buttons are pressed" ); assert( 0 && "compiled without any gamepad supporting library, gamepad will always report that no buttons are pressed" );
warning() << "compiled without any gamepad supporting library, gamepad will always report that no buttons are pressed" << endl; warning() << "compiled without any gamepad supporting library, gamepad will always report that no buttons are pressed" << endl;
#endif #endif
...@@ -33,9 +37,10 @@ GamePad::GamePad( int _n ) ...@@ -33,9 +37,10 @@ GamePad::GamePad( int _n )
mAxes = NULL; mAxes = NULL;
mAxesMultiplier = NULL; mAxesMultiplier = NULL;
mMinSensitivity = 0.0f; mMinSensitivity = 0.0f;
mButtonState = NULL;
mLastButtonState = NULL;
#ifdef ACGL_COMPILE_WITH_GLFW #if defined( ACGL_COMPILE_WITH_GLFW )
mLastGLFWButtonState = NULL;
int numberOfJoysticksFound = 0; int numberOfJoysticksFound = 0;
for (int i = GLFW_JOYSTICK_1; i <= GLFW_JOYSTICK_LAST; ++i) { for (int i = GLFW_JOYSTICK_1; i <= GLFW_JOYSTICK_LAST; ++i) {
if (glfwJoystickPresent(i) == GL_TRUE) { if (glfwJoystickPresent(i) == GL_TRUE) {
...@@ -48,18 +53,32 @@ GamePad::GamePad( int _n ) ...@@ -48,18 +53,32 @@ GamePad::GamePad( int _n )
} }
} }
} }
#elif defined( ACGL_OWN_LINUX_JOYSTICK )
int jsNumber = _n - 1; // the joysticks in /dev/input start counting at 0!
if (jsNumber != 0) {
error() << "only gamepad 0 is supported right now" << std::endl;
}
mGamePadOK = mLinuxGamePad.open( "/dev/input/js0" );
#endif #endif
if (!mGamePadOK) { if (!mGamePadOK) {
mNumberOfButtons = 0; mNumberOfButtons = 0;
mNumberOfAxes = 0; mNumberOfAxes = 0;
#ifdef ACGL_COMPILE_WITH_GLFW #ifdef ACGL_COMPILE_WITH_GLFW
mGLFWButtons = NULL; mGLFWButtons = NULL;
mGLFWAxes = NULL; mGLFWAxes = NULL;
mGLFWGamePadNumber = 0; mGLFWGamePadNumber = 0;
#endif #endif
} else { } else {
update(); // gamepad was found, get number of buttons/axes
#if defined(ACGL_COMPILE_WITH_GLFW)
mGLFWButtons = glfwGetJoystickButtons( mGLFWGamePadNumber, &mNumberOfButtons );
mGLFWAxes = glfwGetJoystickAxes( mGLFWGamePadNumber, &mNumberOfAxes );
#elif defined( ACGL_OWN_LINUX_JOYSTICK )
mNumberOfButtons = mLinuxGamePad.getNumberOfButtons();
mNumberOfAxes = mLinuxGamePad.getNumberOfAxes();
#endif
} }
// //
...@@ -74,10 +93,18 @@ GamePad::GamePad( int _n ) ...@@ -74,10 +93,18 @@ GamePad::GamePad( int _n )
mAxisMap[i] = GAMEPAD_AXIS_ENUM_SIZE; mAxisMap[i] = GAMEPAD_AXIS_ENUM_SIZE;
} }
#ifdef ACGL_COMPILE_WITH_GLFW mJoystickName = "UNKNOWN";
if (mGamePadOK) { if (mGamePadOK) {
string joystickName = string( glfwGetJoystickName(mGLFWGamePadNumber) ); #if defined( ACGL_COMPILE_WITH_GLFW )
if (joystickName == "Sony PLAYSTATION(R)3 Controller") { mJoystickName = string( glfwGetJoystickName(mGLFWGamePadNumber) );
#elif defined( ACGL_OWN_LINUX_JOYSTICK )
mJoystickName = mLinuxGamePad.getIdentifier();
#endif
debug() << "Gamepad name: " << mJoystickName << std::endl;
}
if (mGamePadOK) {
if (mJoystickName == "Sony PLAYSTATION(R)3 Controller") {
setButtonMapping( SELECT, 0); setButtonMapping( SELECT, 0);
setButtonMapping( START, 3); setButtonMapping( START, 3);
setButtonMapping( LEFT_PAD_NORTH , 4); setButtonMapping( LEFT_PAD_NORTH , 4);
...@@ -101,7 +128,7 @@ GamePad::GamePad( int _n ) ...@@ -101,7 +128,7 @@ GamePad::GamePad( int _n )
setAxisMapping( RIGHT_ANALOG_STICK_Y , 3); setAxisMapping( RIGHT_ANALOG_STICK_Y , 3);
setMinAxisSensitivity( 0.05f ); setMinAxisSensitivity( 0.05f );
} else if (joystickName == "Microsoft X-Box 360 pad") { } else if (mJoystickName == "Microsoft X-Box 360 pad") {
setButtonMapping( SELECT, 6); setButtonMapping( SELECT, 6);
setButtonMapping( START, 7); setButtonMapping( START, 7);
//setButtonMapping( LEFT_PAD_NORTH , 0); //setButtonMapping( LEFT_PAD_NORTH , 0);
...@@ -126,30 +153,29 @@ GamePad::GamePad( int _n ) ...@@ -126,30 +153,29 @@ GamePad::GamePad( int _n )
setMinAxisSensitivity( 0.2f ); setMinAxisSensitivity( 0.2f );
} else { } else {
debug() << "unknown gamepad: " << joystickName << endl; debug() << "unknown gamepad: " << mJoystickName << " can't configure buttons" << endl;
} }
} }
#endif
} }
GamePad::~GamePad() GamePad::~GamePad()
{ {
#ifdef ACGL_COMPILE_WITH_GLFW #if defined( ACGL_COMPILE_WITH_GLFW )
delete[] mLastGLFWButtonState;
#elif defined( ACGL_OWN_LINUX_JOYSTICK )
mLinuxGamePad.close();
#endif #endif
delete[] mAxes; delete[] mAxes;
delete[] mAxesMultiplier; delete[] mAxesMultiplier;
delete[] mButtonState;
delete[] mLastButtonState;
} }
bool GamePad::isPressedRaw( unsigned int _button ) bool GamePad::isPressedRaw( unsigned int _button )
{ {
if ( (int)_button > mNumberOfButtons) return false; if ( (int)_button > mNumberOfButtons) return false;
#ifdef ACGL_COMPILE_WITH_GLFW return ( mButtonState[_button] == 1 );
return ( mGLFWButtons[_button] == 1 );
#else
return false;
#endif
} }
bool GamePad::isPressed( GamePadButton _button ) bool GamePad::isPressed( GamePadButton _button )
...@@ -167,11 +193,7 @@ bool GamePad::buttonStateChanged( unsigned int _button ) ...@@ -167,11 +193,7 @@ bool GamePad::buttonStateChanged( unsigned int _button )
{ {
if ( (int)_button > mNumberOfButtons) return false; if ( (int)_button > mNumberOfButtons) return false;
#ifdef ACGL_COMPILE_WITH_GLFW return (mButtonState[_button] != mLastButtonState[_button]);
return (mGLFWButtons[_button] != mLastGLFWButtonState[_button]);
#else
return false;
#endif
} }
...@@ -211,36 +233,83 @@ void GamePad::invertAxis( int _axis, bool _invert ) ...@@ -211,36 +233,83 @@ void GamePad::invertAxis( int _axis, bool _invert )
mAxesMultiplier[_axis] = (_invert)? -1.0f : 1.0f; mAxesMultiplier[_axis] = (_invert)? -1.0f : 1.0f;
} }
void GamePad::update() void GamePad::getAxisAndButtonValues()
{ {
if (!ok()) return; //
// get fresh state:
#ifdef ACGL_COMPILE_WITH_GLFW #ifdef ACGL_COMPILE_WITH_GLFW
if (!mLastGLFWButtonState) { mGLFWButtons = glfwGetJoystickButtons( mGLFWGamePadNumber, &mNumberOfButtons );
mGLFWButtons = glfwGetJoystickButtons( mGLFWGamePadNumber, &mNumberOfButtons ); mGLFWAxes = glfwGetJoystickAxes( mGLFWGamePadNumber, &mNumberOfAxes );
mGLFWAxes = glfwGetJoystickAxes( mGLFWGamePadNumber, &mNumberOfAxes ); memcpy( mButtonState, mGLFWButtons, mNumberOfButtons*sizeof(float) );
memcpy( mAxes, mGLFWAxes, mNumberOfAxes );
#elif defined( ACGL_OWN_LINUX_JOYSTICK )
EventJoystick event;
while (mLinuxGamePad.pollEventButton( event )) {
//debug() << "B time " << event.time << " value " << event.value << " number " << event.number << " synthetic " << event.synthetic << endl;
//debug() << "B value " << event.value << " number " << (int)event.number << " synthetic " << event.synthetic << endl;
if (event.synthetic == 0) {
mButtonState[ event.number ] = (unsigned char) event.value;
}
}
while (mLinuxGamePad.pollEventAxis( event )) {
//debug() << "A time " << event.time << " value " << event.value << " number " << event.number << " synthetic " << event.synthetic << endl;
//debug() << "A value " << event.value << " number " << (int)event.number << " synthetic " << event.synthetic << endl;
if (event.synthetic == 0) {
mAxes[ event.number ] = (float) event.value / 32767.0f; // values a bit over 1, but this will later be clamped
}
}
#else
for (int i = 0; i < mNumberOfButtons; ++i) {
mButtonState[i] = 0;
}
for (int i = 0; i < mNumberOfAxes; ++i) {
mAxes[i] = 0.0f;
}*/
#endif
}
mLastGLFWButtonState = new unsigned char[mNumberOfButtons]; void GamePad::update()
mAxes = new float[mNumberOfAxes]; {
mAxesMultiplier = new float[mNumberOfAxes]; if (!ok()) return;
//
// if needed create state arrays
if (!mLastButtonState) {
mLastButtonState = new unsigned char[mNumberOfButtons];
mButtonState = new unsigned char[mNumberOfButtons];
mAxes = new float[mNumberOfAxes];
mAxesMultiplier = new float[mNumberOfAxes];
for (int i = 0; i < mNumberOfButtons; ++i) {
mButtonState[i] = 0;
}
for (int i = 0; i < mNumberOfAxes; ++i) { for (int i = 0; i < mNumberOfAxes; ++i) {
mAxesMultiplier[i] = 1.0f; mAxesMultiplier[i] = 1.0f;
mAxes[i] = 0.0f; // TODO: depending on the controller, the neutral state can also be -1!
} }
} }
memcpy( mLastGLFWButtonState, mGLFWButtons, mNumberOfButtons );
mGLFWButtons = glfwGetJoystickButtons( mGLFWGamePadNumber, &mNumberOfButtons ); //
mGLFWAxes = glfwGetJoystickAxes( mGLFWGamePadNumber, &mNumberOfAxes ); // store old button state
// old axis state is not stored as this changes nearly constantly anyway
memcpy( mLastButtonState, mButtonState, mNumberOfButtons ); // arrays are unsigned char
memcpy( mAxes, mGLFWAxes, mNumberOfAxes*sizeof(float) ); //
#endif // get raw state:
getAxisAndButtonValues();
//
// scale the axes:
for (int i = 0; i < mNumberOfAxes; ++i) { for (int i = 0; i < mNumberOfAxes; ++i) {
float tmp = std::abs( mAxes[ i ] ); float tmp = std::abs( mAxes[ i ] );
tmp -= mMinSensitivity; tmp -= mMinSensitivity;
if (tmp < 0.0f) tmp = 0.0f; if (tmp < 0.0f) tmp = 0.0f;
tmp /= (1.0f - mMinSensitivity); // rescaled to 0..1 tmp /= (1.0f - mMinSensitivity); // rescaled to 0..1
tmp = glm::clamp( tmp, 0.0f, 1.0f );
float sign = ((mAxes[ i ] < 0.0f) && (tmp != 0.0f)) ? -1.0f : 1.0f; float sign = ((mAxes[ i ] < 0.0f) && (tmp != 0.0f)) ? -1.0f : 1.0f;
mAxes[ i ] = tmp * sign; mAxes[ i ] = tmp * sign;
} }
...@@ -248,7 +317,7 @@ void GamePad::update() ...@@ -248,7 +317,7 @@ void GamePad::update()
void GamePad::printState() void GamePad::printState()
{ {
#ifndef ACGL_COMPILE_WITH_GLFW #ifdef ACGL_NO_GAMEPAD_SUPPORT
warning() << "compiled without any gamepad supporting library, gamepad will always report that no buttons are pressed" << endl; warning() << "compiled without any gamepad supporting library, gamepad will always report that no buttons are pressed" << endl;
return; return;
#endif #endif
...@@ -258,14 +327,12 @@ void GamePad::printState() ...@@ -258,14 +327,12 @@ void GamePad::printState()
return; return;
} }
#ifdef ACGL_COMPILE_WITH_GLFW
for (int i = 0; i < mNumberOfButtons; ++i) { for (int i = 0; i < mNumberOfButtons; ++i) {
debug() << (int) mGLFWButtons[i] << " "; debug() << (int) mButtonState[i] << " ";
} }
debug() << "| "; debug() << "| ";
for (int i = 0; i < mNumberOfAxes; ++i) { for (int i = 0; i < mNumberOfAxes; ++i) {
debug() << mAxes[i] << " "; debug() << mAxes[i] << " ";
} }
debug() << endl; debug() << endl;
#endif
} }
...@@ -185,7 +185,9 @@ const string &Joystick::getIdentifier () ...@@ -185,7 +185,9 @@ const string &Joystick::getIdentifier ()
bool Joystick::pollEventButton(EventJoystick &_event) bool Joystick::pollEventButton(EventJoystick &_event)
{ {
if ( mEventsBtn.size() == 0 ) return false; if ( mEventsBtn.size() == 0 ) {
return false;
}
QMutexLocker locker(&mBtnMutex); QMutexLocker locker(&mBtnMutex);
(void)locker; (void)locker;
...@@ -194,7 +196,6 @@ bool Joystick::pollEventButton(EventJoystick &_event) ...@@ -194,7 +196,6 @@ bool Joystick::pollEventButton(EventJoystick &_event)
{ {
EventJoystick ev = mEventsBtn.front(); EventJoystick ev = mEventsBtn.front();
mEventsBtn.pop(); mEventsBtn.pop();
_event = ev; _event = ev;
return true; return true;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment