GamePad.cc 15.3 KB
Newer Older
Robert Menzel's avatar
Robert Menzel committed
1 2 3 4 5 6 7 8
/***********************************************************************
 * Copyright 2011-2013 Computer Graphics Group RWTH Aachen University. *
 * All rights reserved.                                                *
 * Distributed under the terms of the MIT License (see LICENSE.TXT).   *
 **********************************************************************/

#include <ACGL/HardwareSupport/GamePad.hh>
#include <ACGL/Utils/Log.hh>
9
#include <ACGL/Math/Math.hh>
Robert Menzel's avatar
Robert Menzel committed
10 11 12 13 14 15 16
#include <cassert>
#include <cstring>

#ifdef ACGL_COMPILE_WITH_GLFW
#include <GLFW/glfw3.h>
#endif

17 18 19 20
#if !defined(ACGL_COMPILE_WITH_GLFW) && !defined(ACGL_OWN_LINUX_JOYSTICK)
#define ACGL_NO_GAMEPAD_SUPPORT
#endif

Robert Menzel's avatar
Robert Menzel committed
21 22 23 24 25 26 27 28 29 30
using namespace std;
using namespace ACGL;
using namespace ACGL::Utils;
using namespace ACGL::HardwareSupport;

//! connects to the _n-th joystick
GamePad::GamePad( int _n )
{
    assert( _n != 0 );

31
#ifdef ACGL_NO_GAMEPAD_SUPPORT
32 33 34 35
    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

Robert Menzel's avatar
Robert Menzel committed
36
    mGamePadOK = false;
37 38 39 40 41
    mAxes            = NULL;
    mAxesMultiplier  = NULL;
    mAxesAdd         = NULL;
    mMinSensitivity  = 0.0f;
    mButtonState     = NULL;
42
    mLastButtonState = NULL;
Robert Menzel's avatar
Robert Menzel committed
43

44
#if defined( ACGL_COMPILE_WITH_GLFW )
Robert Menzel's avatar
Robert Menzel committed
45 46 47 48 49 50 51 52 53 54 55 56
    int numberOfJoysticksFound = 0;
    for (int i = GLFW_JOYSTICK_1; i <= GLFW_JOYSTICK_LAST; ++i) {
        if (glfwJoystickPresent(i) == GL_TRUE) {
            numberOfJoysticksFound++;

            if ( numberOfJoysticksFound == _n) {
                mGamePadOK = true;
                mGLFWGamePadNumber = i;
                break;
            }
        }
    }
57 58 59 60 61 62
#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" );
Robert Menzel's avatar
Robert Menzel committed
63 64 65 66
#endif

    if (!mGamePadOK) {
        mNumberOfButtons = 0;
67
        mNumberOfAxes    = 0;
Robert Menzel's avatar
Robert Menzel committed
68 69 70 71 72 73
#ifdef ACGL_COMPILE_WITH_GLFW
        mGLFWButtons = NULL;
        mGLFWAxes    = NULL;
        mGLFWGamePadNumber = 0;
#endif
    } else {
74 75 76 77 78 79 80 81 82
        // 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
Robert Menzel's avatar
Robert Menzel committed
83 84
    }

85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
    //
    // init state arrays:
    //
    mLastButtonState = new unsigned char[mNumberOfButtons];
    mButtonState     = new unsigned char[mNumberOfButtons];
    mAxes            = new float[mNumberOfAxes];
    mAxesMultiplier  = new float[mNumberOfAxes];
    mAxesAdd         = new float[mNumberOfAxes];

    for (int i = 0; i < mNumberOfButtons; ++i) {
        mButtonState[i] = 0;
    }
    for (int i = 0; i < mNumberOfAxes; ++i) {
        mAxesMultiplier[i] = 1.0f;
        mAxesAdd[i] = 0.0f;
        mAxes[i]    = 0.0f;
    }

Robert Menzel's avatar
Robert Menzel committed
103 104 105 106 107 108 109 110 111 112 113 114
    //
    // prepare button mapping
    //
    for (int i = 0; i < GAMEPAD_BUTTON_ENUM_SIZE; ++i) {
        // set to an invalid button number so it will always get reported as false:
        mButtonMap[i] = GAMEPAD_BUTTON_ENUM_SIZE;
    }
    for (int i = 0; i < GAMEPAD_AXIS_ENUM_SIZE; ++i) {
        // set to an invalid button number so it will always get reported as false:
        mAxisMap[i] = GAMEPAD_AXIS_ENUM_SIZE;
    }

115
    mJoystickName = "UNKNOWN";
Robert Menzel's avatar
Robert Menzel committed
116
    if (mGamePadOK) {
117 118 119 120 121 122 123 124 125
#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) {
126 127
        //                     Linux name                                              MacOS X name
        if ((mJoystickName == "Sony PLAYSTATION(R)3 Controller") || (mJoystickName == "PLAYSTATION(R)3 Controller")) {
Robert Menzel's avatar
Robert Menzel committed
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
            setButtonMapping( SELECT, 0);
            setButtonMapping( START,  3);
            setButtonMapping( LEFT_PAD_NORTH  , 4);
            setButtonMapping( LEFT_PAD_EAST   , 5);
            setButtonMapping( LEFT_PAD_SOUTH  , 6);
            setButtonMapping( LEFT_PAD_WEST   , 7);
            setButtonMapping( RIGHT_PAD_NORTH , 12);
            setButtonMapping( RIGHT_PAD_EAST  , 13);
            setButtonMapping( RIGHT_PAD_SOUTH , 14);
            setButtonMapping( RIGHT_PAD_WEST  , 15);
            setButtonMapping( LEFT_SHOULDER   , 10);
            setButtonMapping( RIGHT_SHOULDER  , 11);
            setButtonMapping( LEFT_TRIGGER    , 8);
            setButtonMapping( RIGHT_TRIGGER   , 9);

143 144
            setAxisMapping( LEFT_ANALOG_TRIGGER  , 12); mAxesMultiplier[12] =  0.5f; mAxesAdd[12] = 0.5f;
            setAxisMapping( RIGHT_ANALOG_TRIGGER , 13); mAxesMultiplier[13] = -0.5f; mAxesAdd[13] = 0.5f;
Robert Menzel's avatar
Robert Menzel committed
145 146 147 148
            setAxisMapping( LEFT_ANALOG_STICK_X  , 0);
            setAxisMapping( LEFT_ANALOG_STICK_Y  , 1);
            setAxisMapping( RIGHT_ANALOG_STICK_X , 2);
            setAxisMapping( RIGHT_ANALOG_STICK_Y , 3);
149 150

            setMinAxisSensitivity( 0.05f );
151
		} else if (mJoystickName == "Microsoft X-Box 360 pad") { // 360 USB gamepad on Linux
152 153

            // real buttons:
154 155 156 157 158 159 160 161 162
            setButtonMapping( SELECT, 6);
            setButtonMapping( START,  7);
            setButtonMapping( RIGHT_PAD_NORTH , 3);
            setButtonMapping( RIGHT_PAD_EAST  , 1);
            setButtonMapping( RIGHT_PAD_SOUTH , 0);
            setButtonMapping( RIGHT_PAD_WEST  , 2);
            setButtonMapping( LEFT_SHOULDER   , 4);
            setButtonMapping( RIGHT_SHOULDER  , 5);

163 164 165 166 167 168 169 170 171 172 173
            // virtual buttons (analog axis values interpreted as buttons):
            // (some buttons on the xbox controller are actually analog axes)
            setButtonMapping( LEFT_PAD_NORTH  , 7+mNumberOfButtons); // axis 7
            setButtonMapping( LEFT_PAD_EAST   , 6+mNumberOfButtons); // axis 6
            setButtonMapping( LEFT_PAD_SOUTH  , 7+mNumberOfButtons+mNumberOfAxes); // axis 7 inverse
            setButtonMapping( LEFT_PAD_WEST   , 6+mNumberOfButtons+mNumberOfAxes); // axis 6 inverse
            setButtonMapping( LEFT_TRIGGER    , 2+mNumberOfButtons); // axis 2
            setButtonMapping( RIGHT_TRIGGER   , 5+mNumberOfButtons); // axis 5

            setAxisMapping( LEFT_ANALOG_TRIGGER  , 2); mAxesMultiplier[2] =  0.5f; mAxesAdd[2] = 0.5f;
            setAxisMapping( RIGHT_ANALOG_TRIGGER , 5); mAxesMultiplier[5] = -0.5f; mAxesAdd[5] = 0.5f;
174 175
            setAxisMapping( LEFT_ANALOG_STICK_X  , 0);
            setAxisMapping( LEFT_ANALOG_STICK_Y  , 1);
176 177
            setAxisMapping( RIGHT_ANALOG_STICK_X , 3); mAxesMultiplier[3] = -1.0f;
            setAxisMapping( RIGHT_ANALOG_STICK_Y , 4); mAxesMultiplier[4] = -1.0f;
178 179

            setMinAxisSensitivity( 0.2f );
180 181


182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
		} else if (mJoystickName == "Microsoft PC-joystick driver") { // 360 USB gamepad on Windows

			// real buttons:
			setButtonMapping(SELECT, 6);
			setButtonMapping(START,  7);
			setButtonMapping(RIGHT_PAD_NORTH, 3);
			setButtonMapping(RIGHT_PAD_EAST,  1);
			setButtonMapping(RIGHT_PAD_SOUTH, 0);
			setButtonMapping(RIGHT_PAD_WEST,  2);
			setButtonMapping(LEFT_SHOULDER,   4);
			setButtonMapping(RIGHT_SHOULDER,  5);
			setButtonMapping(LEFT_PAD_NORTH, 10);
			setButtonMapping(LEFT_PAD_EAST,  11);
			setButtonMapping(LEFT_PAD_SOUTH, 12);
			setButtonMapping(LEFT_PAD_WEST,  13);


			//setButtonMapping(LEFT_TRIGGER,  2 + mNumberOfButtons); // axis 2
			//setButtonMapping(RIGHT_TRIGGER, 5 + mNumberOfButtons); // axis 5

			setAxisMapping(LEFT_ANALOG_TRIGGER, 2); mAxesMultiplier[2] = 0.5f; mAxesAdd[2] = 0.5f;
			setAxisMapping(RIGHT_ANALOG_TRIGGER, 5); mAxesMultiplier[5] = -0.5f; mAxesAdd[5] = 0.5f;
			setAxisMapping(LEFT_ANALOG_STICK_X, 0);
			setAxisMapping(LEFT_ANALOG_STICK_Y, 1);
			setAxisMapping(RIGHT_ANALOG_STICK_X, 3); mAxesMultiplier[3] = -1.0f;
			setAxisMapping(RIGHT_ANALOG_STICK_Y, 4); mAxesMultiplier[4] = -1.0f;

			setMinAxisSensitivity(0.2f);


		} else {
213
            debug() << "unknown gamepad: " << mJoystickName << " can't configure buttons" << endl;
Robert Menzel's avatar
Robert Menzel committed
214 215 216 217 218 219
        }
    }
}

GamePad::~GamePad()
{
220 221 222 223
#if defined( ACGL_COMPILE_WITH_GLFW )

#elif defined( ACGL_OWN_LINUX_JOYSTICK )
    mLinuxGamePad.close();
224
#endif
225 226
    delete[] mAxes;
    delete[] mAxesMultiplier;
227
    delete[] mAxesAdd;
228 229
    delete[] mButtonState;
    delete[] mLastButtonState;
Robert Menzel's avatar
Robert Menzel committed
230 231 232 233
}

bool GamePad::isPressedRaw( unsigned int _button )
{
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
    if ( (int)_button < mNumberOfButtons) {
        // it's a button:
        return ( mButtonState[_button] == 1 );
    }
    // "buttons" from mNumberOfButtons to (mNumberOfButtons+mNumberOfAxes-1) are
    // pushed if the axis value is >= 0.5.
    int axis = (int)_button - mNumberOfButtons;
    if (axis < mNumberOfAxes) {
        return (mAxes[axis] >= 0.5f);
    }
    // "buttons" from (mNumberOfButtons+mNumberOfAxes) to (mNumberOfButtons+2*mNumberOfAxes-1) are
    // pushed if the axis value is <= -0.5.
    axis = axis - mNumberOfAxes;
    if (axis < mNumberOfAxes) {
        return (mAxes[axis] <= -0.5f);
    }
    // else the input was just too high, so return false
    return false;
Robert Menzel's avatar
Robert Menzel committed
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
}

bool GamePad::isPressed( GamePadButton _button )
{
    return isPressedRaw( mButtonMap[_button] );
}

void GamePad::setButtonMapping( GamePadButton _button, unsigned int _rawButtonNumber )
{
    assert(_button < GAMEPAD_BUTTON_ENUM_SIZE);
    mButtonMap[_button] = _rawButtonNumber;
}

bool GamePad::buttonStateChanged( unsigned int _button )
{
    if ( (int)_button > mNumberOfButtons) return false;

269
    return (mButtonState[_button] != mLastButtonState[_button]);
Robert Menzel's avatar
Robert Menzel committed
270 271 272 273 274 275 276 277 278 279 280
}


bool GamePad::buttonStateChanged( GamePadButton _button )
{
    return buttonStateChanged( mButtonMap[_button] );
}

float GamePad::getAxisRaw( unsigned int _axis )
{
    if ( (int)_axis > mNumberOfAxes) return 0.0f;
281
    return mAxes[_axis];
Robert Menzel's avatar
Robert Menzel committed
282 283 284 285 286 287 288 289 290 291 292 293 294
}

float GamePad::getAxis( GamePadAxis _axis )
{
    return getAxisRaw( mAxisMap[_axis] );
}

void GamePad::setAxisMapping( GamePadAxis _axis, unsigned int _rawAxisNumber )
{
    assert(_axis < GAMEPAD_AXIS_ENUM_SIZE);
    mAxisMap[_axis] = _rawAxisNumber;
}

295 296 297 298 299 300 301 302 303 304 305 306 307
void GamePad::setMinAxisSensitivity( float _sensitivity )
{
    assert( _sensitivity >= 0.0f && "sensitivity can't be negative" );
    assert( _sensitivity <  1.0f && "sensitivity has to be smaller than one" );

    mMinSensitivity = _sensitivity;
}

void GamePad::invertAxis( int _axis, bool _invert )
{
    assert(_axis < GAMEPAD_AXIS_ENUM_SIZE);
    mAxesMultiplier[_axis] = (_invert)? -1.0f : 1.0f;
}
Robert Menzel's avatar
Robert Menzel committed
308

309
void GamePad::getAxisAndButtonValues()
Robert Menzel's avatar
Robert Menzel committed
310
{
311 312
    //
    // get fresh state:
Robert Menzel's avatar
Robert Menzel committed
313
#ifdef ACGL_COMPILE_WITH_GLFW
314 315
    mGLFWButtons = glfwGetJoystickButtons( mGLFWGamePadNumber, &mNumberOfButtons );
    mGLFWAxes    = glfwGetJoystickAxes(    mGLFWGamePadNumber, &mNumberOfAxes );
Robert Menzel's avatar
Robert Menzel committed
316 317
    memcpy( mButtonState, mGLFWButtons, mNumberOfButtons );
    memcpy( mAxes,        mGLFWAxes,    mNumberOfAxes   * sizeof(float) );
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
#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;
Robert Menzel's avatar
Robert Menzel committed
344
    }
345
#endif
346 347 348 349

    for (int i = 0; i < mNumberOfAxes; ++i) {
        mAxes[i] = mAxes[i] * mAxesMultiplier[i] + mAxesAdd[i];
    }
350
}
Robert Menzel's avatar
Robert Menzel committed
351

352 353 354
void GamePad::update()
{
    if (!ok()) return;
355

356 357 358 359
    //
    // store old button state
    // old axis state is not stored as this changes nearly constantly anyway
    memcpy( mLastButtonState, mButtonState, mNumberOfButtons ); // arrays are unsigned char
360

361 362 363
    //
    // get raw state:
    getAxisAndButtonValues();
364

365 366
    //
    // scale the axes:
367 368 369 370 371
    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
372
        tmp = glm::clamp( tmp, 0.0f, 1.0f );
373 374 375
        float sign = ((mAxes[ i ] < 0.0f) && (tmp != 0.0f)) ? -1.0f : 1.0f;
        mAxes[ i ] = tmp * sign;
    }
376 377 378
	//debug().unmute();
	//printState();
	//debug().mute();
Robert Menzel's avatar
Robert Menzel committed
379 380 381 382
}

void GamePad::printState()
{
383
#ifdef ACGL_NO_GAMEPAD_SUPPORT
384 385 386 387 388 389 390 391
    warning() << "compiled without any gamepad supporting library, gamepad will always report that no buttons are pressed" << endl;
    return;
#endif

    if (!ok()) {
        debug() << "no gamepad found - restarting the application might be needed after plugging in a gamepad" << endl;
        return;
    }
Robert Menzel's avatar
Robert Menzel committed
392 393

    for (int i = 0; i < mNumberOfButtons; ++i) {
394
        debug() << (int) mButtonState[i] << " ";
Robert Menzel's avatar
Robert Menzel committed
395 396
    }
    debug() << "| ";
397 398 399 400

    std::stringstream axes;
    axes.precision(2);
    axes.setf( std::ios::fixed );
Robert Menzel's avatar
Robert Menzel committed
401
    for (int i = 0; i < mNumberOfAxes; ++i) {
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
        axes << mAxes[i] << "  ";
    }
    debug() << axes.str() << endl;
}

bool GamePad::isMapped( GamePadButton _button )
{
    for (int i = 0; i < GAMEPAD_BUTTON_ENUM_SIZE; ++i)
    {
        if (mButtonMap[i] != GAMEPAD_BUTTON_ENUM_SIZE) return true;
    }
    return false;
}

void GamePad::printPressedButtonHelper( GamePadButton _b, const char *_TRUE, const char *_false )
{
    if (isMapped( _b )) {
        if (isPressed( _b )) {
            debug() << _TRUE << " ";
        } else {
            debug() << _false << " ";
        }
Robert Menzel's avatar
Robert Menzel committed
424
    }
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
}

void GamePad::printPressedButtons()
{
    printPressedButtonHelper( SELECT, "SELECT", "select" );
    printPressedButtonHelper( START, "START", "start" );
    printPressedButtonHelper( LEFT_PAD_NORTH,  "L_PAD_N", "l_pad_n");
    printPressedButtonHelper( LEFT_PAD_EAST,   "L_PAD_E", "l_pad_e");
    printPressedButtonHelper( LEFT_PAD_SOUTH,  "L_PAD_S", "l_pad_s");
    printPressedButtonHelper( LEFT_PAD_WEST,   "L_PAD_W", "l_pad_w");
    printPressedButtonHelper( RIGHT_PAD_NORTH, "R_PAD_N", "r_pad_n");
    printPressedButtonHelper( RIGHT_PAD_EAST,  "R_PAD_E", "r_pad_e");
    printPressedButtonHelper( RIGHT_PAD_SOUTH, "R_PAD_S", "r_pad_s");
    printPressedButtonHelper( RIGHT_PAD_WEST,  "R_PAD_W", "r_pad_w");
    printPressedButtonHelper( LEFT_SHOULDER,   "L_SHOULDER", "l_shoulder");
    printPressedButtonHelper( RIGHT_SHOULDER,  "R_SHOULDER", "r_shoulder");
    printPressedButtonHelper( LEFT_TRIGGER,    "L_TRIGGER", "l_trigger");
    printPressedButtonHelper( RIGHT_TRIGGER,   "R_TRIGGER", "r_trigger");
Robert Menzel's avatar
Robert Menzel committed
443 444
    debug() << endl;
}