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

added joystick support for QT/linux

parent 5a1cf05f
......@@ -14,7 +14,7 @@ namespace ACGL{
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 {
public:
......@@ -107,20 +107,32 @@ private:
int mNumberOfAxes;
int mButtonMap[GAMEPAD_BUTTON_ENUM_SIZE];
int mAxisMap[GAMEPAD_AXIS_ENUM_SIZE];
float *mAxes;
float *mAxesMultiplier;
float mMinSensitivity;
unsigned char *mButtonState; // 0 = released, 1 = pressed
unsigned char *mLastButtonState;
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
//
#ifdef ACGL_COMPILE_WITH_GLFW
const unsigned char *mGLFWButtons;
const float *mGLFWAxes;
unsigned char *mLastGLFWButtonState;
const unsigned char *mGLFWButtons; // temp. used as GLFW needs a const array
const float *mGLFWAxes; // temp. used as GLFW needs a const array
int mGLFWGamePadNumber;
#endif
//
// Custom Linux Joystick support:
//
#ifdef ACGL_OWN_LINUX_JOYSTICK
Joystick mLinuxGamePad;
#endif
};
ACGL_SMARTPOINTER_TYPEDEFS(GamePad)
......
......@@ -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.
//
#if defined(ACGL_COMPILE_WITH_QT) && defined(__linux__) && defined(ACGL_EXPERIMENTAL)
#if defined(ACGL_COMPILE_WITH_QT) && defined(__linux__)
#define ACGL_OWN_LINUX_JOYSTICK
#endif
......@@ -60,8 +60,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
struct EventJoystick
{
int32_t time;
int16_t value;
int32_t time; // seconds till unix
int16_t value; // -32k .. 32k
int8_t number;
bool synthetic;
};
......
......@@ -14,6 +14,10 @@
#include <GLFW/glfw3.h>
#endif
#if !defined(ACGL_COMPILE_WITH_GLFW) && !defined(ACGL_OWN_LINUX_JOYSTICK)
#define ACGL_NO_GAMEPAD_SUPPORT
#endif
using namespace std;
using namespace ACGL;
using namespace ACGL::Utils;
......@@ -24,7 +28,7 @@ GamePad::GamePad( int _n )
{
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" );
warning() << "compiled without any gamepad supporting library, gamepad will always report that no buttons are pressed" << endl;
#endif
......@@ -33,9 +37,10 @@ GamePad::GamePad( int _n )
mAxes = NULL;
mAxesMultiplier = NULL;
mMinSensitivity = 0.0f;
mButtonState = NULL;
mLastButtonState = NULL;
#ifdef ACGL_COMPILE_WITH_GLFW
mLastGLFWButtonState = NULL;
#if defined( ACGL_COMPILE_WITH_GLFW )
int numberOfJoysticksFound = 0;
for (int i = GLFW_JOYSTICK_1; i <= GLFW_JOYSTICK_LAST; ++i) {
if (glfwJoystickPresent(i) == GL_TRUE) {
......@@ -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
if (!mGamePadOK) {
mNumberOfButtons = 0;
mNumberOfAxes = 0;
mNumberOfAxes = 0;
#ifdef ACGL_COMPILE_WITH_GLFW
mGLFWButtons = NULL;
mGLFWAxes = NULL;
mGLFWGamePadNumber = 0;
#endif
} 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 )
mAxisMap[i] = GAMEPAD_AXIS_ENUM_SIZE;
}
#ifdef ACGL_COMPILE_WITH_GLFW
mJoystickName = "UNKNOWN";
if (mGamePadOK) {
string joystickName = string( glfwGetJoystickName(mGLFWGamePadNumber) );
if (joystickName == "Sony PLAYSTATION(R)3 Controller") {
#if defined( ACGL_COMPILE_WITH_GLFW )
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( START, 3);
setButtonMapping( LEFT_PAD_NORTH , 4);
......@@ -101,7 +128,7 @@ GamePad::GamePad( int _n )
setAxisMapping( RIGHT_ANALOG_STICK_Y , 3);
setMinAxisSensitivity( 0.05f );
} else if (joystickName == "Microsoft X-Box 360 pad") {
} else if (mJoystickName == "Microsoft X-Box 360 pad") {
setButtonMapping( SELECT, 6);
setButtonMapping( START, 7);
//setButtonMapping( LEFT_PAD_NORTH , 0);
......@@ -126,30 +153,29 @@ GamePad::GamePad( int _n )
setMinAxisSensitivity( 0.2f );
} else {
debug() << "unknown gamepad: " << joystickName << endl;
debug() << "unknown gamepad: " << mJoystickName << " can't configure buttons" << endl;
}
}
#endif
}
GamePad::~GamePad()
{
#ifdef ACGL_COMPILE_WITH_GLFW
delete[] mLastGLFWButtonState;
#if defined( ACGL_COMPILE_WITH_GLFW )
#elif defined( ACGL_OWN_LINUX_JOYSTICK )
mLinuxGamePad.close();
#endif
delete[] mAxes;
delete[] mAxesMultiplier;
delete[] mButtonState;
delete[] mLastButtonState;
}
bool GamePad::isPressedRaw( unsigned int _button )
{
if ( (int)_button > mNumberOfButtons) return false;
#ifdef ACGL_COMPILE_WITH_GLFW
return ( mGLFWButtons[_button] == 1 );
#else
return false;
#endif
return ( mButtonState[_button] == 1 );
}
bool GamePad::isPressed( GamePadButton _button )
......@@ -167,11 +193,7 @@ bool GamePad::buttonStateChanged( unsigned int _button )
{
if ( (int)_button > mNumberOfButtons) return false;
#ifdef ACGL_COMPILE_WITH_GLFW
return (mGLFWButtons[_button] != mLastGLFWButtonState[_button]);
#else
return false;
#endif
return (mButtonState[_button] != mLastButtonState[_button]);
}
......@@ -211,36 +233,83 @@ void GamePad::invertAxis( int _axis, bool _invert )
mAxesMultiplier[_axis] = (_invert)? -1.0f : 1.0f;
}
void GamePad::update()
void GamePad::getAxisAndButtonValues()
{
if (!ok()) return;
//
// get fresh state:
#ifdef ACGL_COMPILE_WITH_GLFW
if (!mLastGLFWButtonState) {
mGLFWButtons = glfwGetJoystickButtons( mGLFWGamePadNumber, &mNumberOfButtons );
mGLFWAxes = glfwGetJoystickAxes( mGLFWGamePadNumber, &mNumberOfAxes );
mGLFWButtons = glfwGetJoystickButtons( mGLFWGamePadNumber, &mNumberOfButtons );
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];
mAxes = new float[mNumberOfAxes];
mAxesMultiplier = new float[mNumberOfAxes];
void GamePad::update()
{
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) {
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) {
float tmp = std::abs( mAxes[ i ] );
tmp -= mMinSensitivity;
if (tmp < 0.0f) tmp = 0.0f;
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;
mAxes[ i ] = tmp * sign;
}
......@@ -248,7 +317,7 @@ void GamePad::update()
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;
return;
#endif
......@@ -258,14 +327,12 @@ void GamePad::printState()
return;
}
#ifdef ACGL_COMPILE_WITH_GLFW
for (int i = 0; i < mNumberOfButtons; ++i) {
debug() << (int) mGLFWButtons[i] << " ";
debug() << (int) mButtonState[i] << " ";
}
debug() << "| ";
for (int i = 0; i < mNumberOfAxes; ++i) {
debug() << mAxes[i] << " ";
}
debug() << endl;
#endif
}
......@@ -185,7 +185,9 @@ const string &Joystick::getIdentifier ()
bool Joystick::pollEventButton(EventJoystick &_event)
{
if ( mEventsBtn.size() == 0 ) return false;
if ( mEventsBtn.size() == 0 ) {
return false;
}
QMutexLocker locker(&mBtnMutex);
(void)locker;
......@@ -194,7 +196,6 @@ bool Joystick::pollEventButton(EventJoystick &_event)
{
EventJoystick ev = mEventsBtn.front();
mEventsBtn.pop();
_event = ev;
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