diff --git a/addons/vehicledamage/XEH_preInit.sqf b/addons/vehicledamage/XEH_preInit.sqf index 91df183b45..ed6a024c2b 100644 --- a/addons/vehicledamage/XEH_preInit.sqf +++ b/addons/vehicledamage/XEH_preInit.sqf @@ -16,6 +16,7 @@ PREP(dispatchDamage); PREP(doHit); // Unique local vehicle ID +GVAR(extensionLibrary) = "z\ace\ace_vd.dll"; GVAR(vehicle_id) = 0; FUNC(_textVector) = { diff --git a/addons/vehicledamage/functions/fnc_callExtension.sqf b/addons/vehicledamage/functions/fnc_callExtension.sqf new file mode 100644 index 0000000000..85f4f11166 --- /dev/null +++ b/addons/vehicledamage/functions/fnc_callExtension.sqf @@ -0,0 +1,7 @@ +#include "script_component.hpp" + +#ifdef ACE_EXTENSION_DYNLOAD + "ace_dynload" callExtension format["ace_dynload:call:%1,%1", GVAR(extensionLibrary), _this]; +#else + "ace_vd" callExtension _this; +#endif \ No newline at end of file diff --git a/addons/vehicledamage/functions/fnc_doHit.sqf b/addons/vehicledamage/functions/fnc_doHit.sqf index 6506036de2..49341ecc78 100644 --- a/addons/vehicledamage/functions/fnc_doHit.sqf +++ b/addons/vehicledamage/functions/fnc_doHit.sqf @@ -49,5 +49,5 @@ _command = format["hit:%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12,%13,%14,%15,%16", VECTOR_TEXT(_projectileVelocity) ]; TRACE_1("", _command); -_result = "ace_vd" callExtension _command; +_result = _command call FUNC(callExtension); TRACE_1("", _result); \ No newline at end of file diff --git a/addons/vehicledamage/functions/fnc_initializeExtension.sqf b/addons/vehicledamage/functions/fnc_initializeExtension.sqf index 7ebc9fbb13..bc7f13d9d1 100644 --- a/addons/vehicledamage/functions/fnc_initializeExtension.sqf +++ b/addons/vehicledamage/functions/fnc_initializeExtension.sqf @@ -1,5 +1,25 @@ #include "script_component.hpp" -GVAR(ready) = false; -CALL_EXT "init:"; +// Initialize our event handlers +GVAR(ready) = false; + +#ifdef ACE_EXTENSION_DYNLOAD +"ace_dynload" callExtension format["load:%1", GVAR(extensionLibrary)]; +#endif + +"init:" call FUNC(callExtension); + +#ifdef ACE_VEHICLEDAMAGE_RENDER_DEBUG +"debug_render:" call FUNC(callExtension); +#endif + +[{ + private["_result"]; + // Wait until the extension is ready + _result = "ready" call FUNC(callExtension); + if(_result == "0") then { + diag_log text format["[ACE] - Vehicle damage extension initialized"]; + GVAR(ready) = true; + }; +}, 0, [] ] CBA_fnc_addPerFrameHandler; \ No newline at end of file diff --git a/addons/vehicledamage/functions/fnc_monitorResultsPFH.sqf b/addons/vehicledamage/functions/fnc_monitorResultsPFH.sqf index abfe95a8e3..c46142303e 100644 --- a/addons/vehicledamage/functions/fnc_monitorResultsPFH.sqf +++ b/addons/vehicledamage/functions/fnc_monitorResultsPFH.sqf @@ -3,10 +3,10 @@ PARAMS_2(_args,_handle); private["_result"]; -_result = "ace_vd" callExtension "fetch_result:1"; +_result = "fetch_result:1" call FUNC(callExtension);; while { _result != "" && {_result != "-1"} } do { TRACE_1("", _result); - _result = "ace_vd" callExtension "fetch_result:1"; + _result = "fetch_result:1" call FUNC(callExtension);; _resultArgs = [_result] call FUNC(parseResult); if(!isNil "_resultArgs") then { diff --git a/addons/vehicledamage/functions/fnc_registerVehicleWithExtension.sqf b/addons/vehicledamage/functions/fnc_registerVehicleWithExtension.sqf index c503e3f587..3106f629e7 100644 --- a/addons/vehicledamage/functions/fnc_registerVehicleWithExtension.sqf +++ b/addons/vehicledamage/functions/fnc_registerVehicleWithExtension.sqf @@ -1,4 +1,4 @@ -#define DEBUG_MODE_FULL +//#define DEBUG_MODE_FULL #include "script_component.hpp" PARAMS_1(_vehicle); @@ -13,6 +13,8 @@ _model = getText (configFile >> "CfgVehicles" >> (typeOf _vehicle) >> "model"); if(_model != "") then { _value = format["register_vehicle:%1,%2,%3",_model,_id,VECTOR_TEXT(getPosASL _vehicle)]; TRACE_1("", _value); - _result = "ace_vd" callExtension _value; + _result = _value call FUNC(callExtension); _vehicle setVariable[QGVAR(id), _id, false]; -}; \ No newline at end of file +}; + +diag_log text format["[ACE] - Vehicle queued for extension loading %1 - %2=[%2]", _id, _vehicle, _model]; \ No newline at end of file diff --git a/addons/vehicledamage/functions/fnc_unregisterWithExtension.sqf b/addons/vehicledamage/functions/fnc_unregisterWithExtension.sqf index 5134e85e13..fd01b95ff9 100644 --- a/addons/vehicledamage/functions/fnc_unregisterWithExtension.sqf +++ b/addons/vehicledamage/functions/fnc_unregisterWithExtension.sqf @@ -7,5 +7,5 @@ if(!GVAR(Enabled)) exitWith {}; _id = _vehicle getVariable[QGVAR(id), -1]; if(_id > 0) then { _id = _vehicle setVariable[QGVAR(id), -1]; - CALL_EXT format["delete_vehicle:%1",_id]; + format["delete_vehicle:%1",_id] call FUNC(callExtension); }; \ No newline at end of file diff --git a/extensions/lib/directxtk/GamePad.cpp b/extensions/lib/directxtk/GamePad.cpp deleted file mode 100644 index 8096a950d8..0000000000 --- a/extensions/lib/directxtk/GamePad.cpp +++ /dev/null @@ -1,957 +0,0 @@ -//-------------------------------------------------------------------------------------- -// File: GamePad.cpp -// -// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF -// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A -// PARTICULAR PURPOSE. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// http://go.microsoft.com/fwlink/?LinkId=248929 -//-------------------------------------------------------------------------------------- - -#include "pch.h" - -#include "GamePad.h" -#include "PlatformHelpers.h" - -using namespace DirectX; - -namespace -{ - float ApplyLinearDeadZone( float value, float maxValue, float deadZoneSize ) - { - if ( value < -deadZoneSize ) - { - // Increase negative values to remove the deadzone discontinuity. - value += deadZoneSize; - } - else if ( value > deadZoneSize ) - { - // Decrease positive values to remove the deadzone discontinuity. - value -= deadZoneSize; - } - else - { - // Values inside the deadzone come out zero. - return 0; - } - - // Scale into 0-1 range. - float scaledValue = value / (maxValue - deadZoneSize); - return std::max( -1.f, std::min( scaledValue, 1.f ) ); - } - - void ApplyStickDeadZone( float x, float y, GamePad::DeadZone deadZoneMode, float maxValue, float deadZoneSize, - _Out_ float& resultX, _Out_ float& resultY) - { - switch( deadZoneMode ) - { - case GamePad::DEAD_ZONE_INDEPENDENT_AXES: - resultX = ApplyLinearDeadZone( x, maxValue, deadZoneSize ); - resultY = ApplyLinearDeadZone( y, maxValue, deadZoneSize ); - break; - - case GamePad::DEAD_ZONE_CIRCULAR: - { - float dist = sqrtf( x*x + y*y ); - float wanted = ApplyLinearDeadZone( dist, maxValue, deadZoneSize ); - - float scale = (wanted > 0.f) ? ( wanted / dist ) : 0.f; - - resultX = std::max( -1.f, std::min( x * scale, 1.f ) ); - resultY = std::max( -1.f, std::min( y * scale, 1.f ) ); - } - break; - - default: // GamePad::DEAD_ZONE_NONE - resultX = ApplyLinearDeadZone( x, maxValue, 0 ); - resultY = ApplyLinearDeadZone( y, maxValue, 0 ); - break; - } - } -} - - -#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) && (_WIN32_WINNT >= 0x0A00) - -// TODO - Windows.Gaming.Input - -class GamePad::Impl -{ -public: - Impl() - { - if ( s_gamePad ) - { - throw std::exception( "GamePad is a singleton" ); - } - - s_gamePad = this; - } - - ~Impl() - { - s_gamePad = nullptr; - } - - void GetState(int player, _Out_ State& state, DeadZone) - { - UNREFERENCED_PARAMETER(player); - - memset( &state, 0, sizeof(State) ); - } - - void GetCapabilities(int player, _Out_ Capabilities& caps) - { - UNREFERENCED_PARAMETER(player); - - memset( &caps, 0, sizeof(Capabilities) ); - } - - bool SetVibration(int player, float leftMotor, float rightMotor, float leftTrigger, float rightTrigger) - { - UNREFERENCED_PARAMETER(player); - UNREFERENCED_PARAMETER(leftMotor); - UNREFERENCED_PARAMETER(rightMotor); - UNREFERENCED_PARAMETER(leftTrigger); - UNREFERENCED_PARAMETER(rightTrigger); - - return false; - } - - void Suspend() - { - } - - void Resume() - { - } - -private: - static GamePad::Impl* s_gamePad; -}; - -GamePad::Impl* GamePad::Impl::s_gamePad = nullptr; - - -#elif defined(_XBOX_ONE) - -//====================================================================================== -// Windows::Xbox::Input -//====================================================================================== - -#include - -#ifdef _TITLE -#include - -namespace -{ - -class GamepadAddedListener : public Microsoft::WRL::RuntimeClass, - ABI::Windows::Foundation::IEventHandler, - Microsoft::WRL::FtmBase> -{ -public: - GamepadAddedListener(HANDLE event) : mEvent(event) {} - - STDMETHOD(Invoke)(_In_ IInspectable *, _In_ ABI::Windows::Xbox::Input::IGamepadAddedEventArgs * ) override - { - SetEvent( mEvent ); - return S_OK; - } - -private: - HANDLE mEvent; -}; - -class GamepadRemovedListener : public Microsoft::WRL::RuntimeClass, - ABI::Windows::Foundation::IEventHandler, - Microsoft::WRL::FtmBase> -{ -public: - GamepadRemovedListener(HANDLE event) : mEvent(event) {} - - STDMETHOD(Invoke)(_In_ IInspectable *, _In_ ABI::Windows::Xbox::Input::IGamepadRemovedEventArgs * ) override - { - SetEvent( mEvent ); - return S_OK; - } - -private: - HANDLE mEvent; -}; - -} -#endif - -class GamePad::Impl -{ -public: - Impl() - { - using namespace Microsoft::WRL; - using namespace Microsoft::WRL::Wrappers; - using namespace ABI::Windows::Foundation; - - mAddedToken.value = 0; - mRemovedToken.value = 0; - - if ( s_changed ) - { - throw std::exception( "GamePad is a singleton" ); - } - - s_changed = CreateEventEx( nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE ); - if ( !s_changed ) - { - throw std::exception( "CreateEventEx" ); - } - - HRESULT hr = GetActivationFactory( HStringReference(RuntimeClass_Windows_Xbox_Input_Gamepad).Get(), mStatics.GetAddressOf() ); - ThrowIfFailed( hr ); - -#ifdef _TITLE - // This is a workaround for some registration issues in the GameOS - - hr = mStatics->add_GamepadAdded(Make(s_changed).Get(), &mAddedToken ); - ThrowIfFailed( hr ); - - hr = mStatics->add_GamepadRemoved(Make(s_changed).Get(), &mRemovedToken ); - ThrowIfFailed( hr ); -#else - typedef __FIEventHandler_1_Windows__CXbox__CInput__CGamepadAddedEventArgs AddedHandler; - hr = mStatics->add_GamepadAdded(Callback(GamepadAdded).Get(), &mAddedToken ); - ThrowIfFailed( hr ); - - typedef __FIEventHandler_1_Windows__CXbox__CInput__CGamepadRemovedEventArgs RemovedHandler; - hr = mStatics->add_GamepadRemoved(Callback(GamepadRemoved).Get(), &mRemovedToken ); - ThrowIfFailed( hr ); -#endif - - ScanGamePads(); - } - - ~Impl() - { - if ( mStatics ) - { - mStatics->remove_GamepadAdded( mAddedToken ); - mStatics->remove_GamepadRemoved( mRemovedToken ); - - mStatics.Reset(); - } - - if ( s_changed ) - { - CloseHandle( s_changed ); - s_changed = nullptr; - } - } - - void GetState( int player, _Out_ State& state, DeadZone deadZoneMode ) - { - using namespace Microsoft::WRL; - using namespace ABI::Windows::Xbox::Input; - - if ( WaitForSingleObjectEx( s_changed, 0, FALSE ) == WAIT_OBJECT_0 ) - { - ScanGamePads(); - } - - if ( ( player >= 0 ) && ( player < MAX_PLAYER_COUNT ) ) - { - if ( mGamePad[ player ] ) - { - RawGamepadReading reading; - HRESULT hr = mGamePad[ player ]->GetRawCurrentReading( &reading ); - if ( SUCCEEDED(hr) ) - { - state.connected = true; - state.packet = reading.Timestamp; - - state.buttons.a = (reading.Buttons & GamepadButtons::GamepadButtons_A) != 0; - state.buttons.b = (reading.Buttons & GamepadButtons::GamepadButtons_B) != 0; - state.buttons.x = (reading.Buttons & GamepadButtons::GamepadButtons_X) != 0; - state.buttons.y = (reading.Buttons & GamepadButtons::GamepadButtons_Y) != 0; - - state.buttons.leftStick = (reading.Buttons& GamepadButtons::GamepadButtons_LeftThumbstick) != 0; - state.buttons.rightStick = (reading.Buttons& GamepadButtons::GamepadButtons_RightThumbstick) != 0; - - state.buttons.leftShoulder = (reading.Buttons& GamepadButtons::GamepadButtons_LeftShoulder) != 0; - state.buttons.rightShoulder = (reading.Buttons& GamepadButtons::GamepadButtons_RightShoulder) != 0; - - state.buttons.back = (reading.Buttons& GamepadButtons::GamepadButtons_View) != 0; - state.buttons.start = (reading.Buttons& GamepadButtons::GamepadButtons_Menu) != 0; - - state.dpad.up = (reading.Buttons & GamepadButtons::GamepadButtons_DPadUp) != 0; - state.dpad.down = (reading.Buttons & GamepadButtons::GamepadButtons_DPadDown) != 0; - state.dpad.right = (reading.Buttons & GamepadButtons::GamepadButtons_DPadRight) != 0; - state.dpad.left = (reading.Buttons & GamepadButtons::GamepadButtons_DPadLeft) != 0; - - ApplyStickDeadZone( reading.LeftThumbstickX, reading.LeftThumbstickY, - deadZoneMode, 1.f, .24f /* Recommend Xbox One deadzone */, - state.thumbSticks.leftX, state.thumbSticks.leftY ); - - ApplyStickDeadZone( reading.RightThumbstickX, reading.RightThumbstickY, - deadZoneMode, 1.f, .24f /* Recommend Xbox One deadzone */, - state.thumbSticks.rightX, state.thumbSticks.rightY ); - - state.triggers.left = reading.LeftTrigger; - state.triggers.right = reading.RightTrigger; - - return; - } - } - } - - memset( &state, 0, sizeof(State) ); - } - - void GetCapabilities( int player, _Out_ Capabilities& caps ) - { - if ( WaitForSingleObjectEx( s_changed, 0, FALSE ) == WAIT_OBJECT_0 ) - { - ScanGamePads(); - } - - if ( ( player >= 0 ) && ( player < MAX_PLAYER_COUNT ) ) - { - if ( mGamePad[ player ] ) - { - caps.connected = true; - caps.gamepadType = Capabilities::GAMEPAD; - - Microsoft::WRL::ComPtr ctrl; - HRESULT hr = mGamePad[ player ].As( &ctrl ); - if ( SUCCEEDED(hr) && ctrl ) - { - hr = ctrl->get_Id( &caps.id ); - if ( FAILED(hr) ) - caps.id = 0; - } - else - caps.id = 0; - - return; - } - } - - memset( &caps, 0, sizeof(Capabilities) ); - } - - bool SetVibration( int player, float leftMotor, float rightMotor, float leftTrigger, float rightTrigger ) - { - using namespace ABI::Windows::Xbox::Input; - - if ( ( player >= 0 ) && ( player < MAX_PLAYER_COUNT ) ) - { - if ( mGamePad[ player ] ) - { - HRESULT hr; - try - { - GamepadVibration vib; - vib.LeftMotorLevel = leftMotor; - vib.RightMotorLevel = rightMotor; - vib.LeftTriggerLevel = leftTrigger; - vib.RightTriggerLevel = rightTrigger; - hr = mGamePad[ player ]->SetVibration(vib); - } - catch( ... ) - { - // Handle case where gamepad might be invalid - hr = E_FAIL; - } - - if ( SUCCEEDED(hr) ) - return true; - } - } - - return false; - } - - void Suspend() - { - for( size_t j = 0; j < MAX_PLAYER_COUNT; ++j ) - { - mGamePad[ j ].Reset(); - } - } - - void Resume() - { - // Make sure we rescan gamepads - SetEvent( s_changed ); - } - -private: - void ScanGamePads() - { - using namespace Microsoft::WRL; - using namespace ABI::Windows::Foundation::Collections; - using namespace ABI::Windows::Xbox::Input; - - ComPtr> pads; - HRESULT hr = mStatics->get_Gamepads( pads.GetAddressOf() ); - ThrowIfFailed( hr ); - - unsigned int count = 0; - pads->get_Size( &count ); - ThrowIfFailed( hr ); - - // Check for removed gamepads - for( size_t j = 0; j < MAX_PLAYER_COUNT; ++j ) - { - if ( mGamePad[ j ] ) - { - unsigned int k = 0; - for( ; k < count; ++k ) - { - ComPtr pad; - hr = pads->GetAt( k, pad.GetAddressOf() ); - if ( SUCCEEDED(hr) && ( pad == mGamePad[ j ] ) ) - { - break; - } - } - - if ( k >= count ) - { - mGamePad[ j ].Reset(); - } - } - } - - // Check for added gamepads - for( unsigned int j = 0; j < count; ++j ) - { - ComPtr pad; - hr = pads->GetAt( j, pad.GetAddressOf() ); - if ( SUCCEEDED(hr) ) - { - size_t empty = MAX_PLAYER_COUNT; - size_t k = 0; - for( ; k < MAX_PLAYER_COUNT; ++k ) - { - if ( mGamePad[ k ] == pad ) - { - break; - } - else if ( !mGamePad[ k ] ) - { - if ( empty >= MAX_PLAYER_COUNT ) - empty = k; - } - } - - if ( k >= MAX_PLAYER_COUNT ) - { - if ( empty >= MAX_PLAYER_COUNT ) - { - throw std::exception( "Too many gamepads found" ); - } - - mGamePad[ empty ] = pad; - } - } - } - } - - Microsoft::WRL::ComPtr mStatics; - Microsoft::WRL::ComPtr mGamePad[ MAX_PLAYER_COUNT ]; - - EventRegistrationToken mAddedToken; - EventRegistrationToken mRemovedToken; - - static HANDLE s_changed; - -#ifndef _TITLE - static HRESULT GamepadAdded( IInspectable *, ABI::Windows::Xbox::Input::IGamepadAddedEventArgs * ) - { - SetEvent( s_changed ); - return S_OK; - } - - static HRESULT GamepadRemoved( IInspectable *, ABI::Windows::Xbox::Input::IGamepadRemovedEventArgs* ) - { - SetEvent( s_changed ); - return S_OK; - } -#endif -}; - -HANDLE GamePad::Impl::s_changed = nullptr; - - -#elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) - -//====================================================================================== -// Null device for Windows Phone -//====================================================================================== - -class GamePad::Impl -{ -public: - Impl() - { - if ( s_gamePad ) - { - throw std::exception( "GamePad is a singleton" ); - } - - s_gamePad = this; - } - - ~Impl() - { - s_gamePad = nullptr; - } - - void GetState(int player, _Out_ State& state, DeadZone) - { - UNREFERENCED_PARAMETER(player); - - memset( &state, 0, sizeof(State) ); - } - - void GetCapabilities(int player, _Out_ Capabilities& caps) - { - UNREFERENCED_PARAMETER(player); - - memset( &caps, 0, sizeof(Capabilities) ); - } - - bool SetVibration(int player, float leftMotor, float rightMotor, float leftTrigger, float rightTrigger) - { - UNREFERENCED_PARAMETER(player); - UNREFERENCED_PARAMETER(leftMotor); - UNREFERENCED_PARAMETER(rightMotor); - UNREFERENCED_PARAMETER(leftTrigger); - UNREFERENCED_PARAMETER(rightTrigger); - - return false; - } - - void Suspend() - { - } - - void Resume() - { - } - -private: - static GamePad::Impl* s_gamePad; -}; - -GamePad::Impl* GamePad::Impl::s_gamePad = nullptr; - - -#else - -//====================================================================================== -// XInput -//====================================================================================== - -#include - -static_assert( GamePad::MAX_PLAYER_COUNT == XUSER_MAX_COUNT, "xinput.h mismatch" ); - -class GamePad::Impl -{ -public: - Impl() - { - for( int j = 0; j < XUSER_MAX_COUNT; ++j ) - { - ClearSlot( j, 0 ); - } - -#if (_WIN32_WINNT < _WIN32_WINNT_WIN8) - mSuspended = false; -#endif - - if ( s_gamePad ) - { - throw std::exception( "GamePad is a singleton" ); - } - - s_gamePad = this; - } - - ~Impl() - { - s_gamePad = nullptr; - } - - void GetState( int player, _Out_ State& state, DeadZone deadZoneMode ) - { - if ( !ThrottleRetry(player) ) - { -#if (_WIN32_WINNT < _WIN32_WINNT_WIN8) - if ( mSuspended ) - { - memset( &state, 0, sizeof(State) ); - state.connected = mConnected[ player ]; - return; - } -#endif - - XINPUT_STATE xstate; - DWORD result = XInputGetState( DWORD(player), &xstate ); - if ( result == ERROR_DEVICE_NOT_CONNECTED ) - { - ClearSlot( player, GetTickCount64() ); - } - else - { - mConnected[ player ] = true; - - state.connected = true; - state.packet = xstate.dwPacketNumber; - - WORD xbuttons = xstate.Gamepad.wButtons; - state.buttons.a = (xbuttons & XINPUT_GAMEPAD_A) != 0; - state.buttons.b = (xbuttons & XINPUT_GAMEPAD_B) != 0; - state.buttons.x = (xbuttons & XINPUT_GAMEPAD_X) != 0; - state.buttons.y = (xbuttons & XINPUT_GAMEPAD_Y) != 0; - state.buttons.leftStick = (xbuttons & XINPUT_GAMEPAD_LEFT_THUMB) != 0; - state.buttons.rightStick = (xbuttons & XINPUT_GAMEPAD_RIGHT_THUMB) != 0; - state.buttons.leftShoulder = (xbuttons & XINPUT_GAMEPAD_LEFT_SHOULDER) != 0; - state.buttons.rightShoulder = (xbuttons & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0; - state.buttons.back = (xbuttons & XINPUT_GAMEPAD_BACK) != 0; - state.buttons.start = (xbuttons & XINPUT_GAMEPAD_START) != 0; - - state.dpad.up = (xbuttons & XINPUT_GAMEPAD_DPAD_UP) != 0; - state.dpad.down = (xbuttons & XINPUT_GAMEPAD_DPAD_DOWN) != 0; - state.dpad.right = (xbuttons & XINPUT_GAMEPAD_DPAD_RIGHT) != 0; - state.dpad.left = (xbuttons & XINPUT_GAMEPAD_DPAD_LEFT) != 0; - - if ( deadZoneMode == DEAD_ZONE_NONE ) - { - state.triggers.left = ApplyLinearDeadZone( float(xstate.Gamepad.bLeftTrigger), 255.f, 0.f ); - state.triggers.right = ApplyLinearDeadZone( float(xstate.Gamepad.bRightTrigger), 255.f, 0.f ); - } - else - { - state.triggers.left = ApplyLinearDeadZone( float(xstate.Gamepad.bLeftTrigger), 255.f, float(XINPUT_GAMEPAD_TRIGGER_THRESHOLD) ); - state.triggers.right = ApplyLinearDeadZone( float(xstate.Gamepad.bRightTrigger), 255.f, float(XINPUT_GAMEPAD_TRIGGER_THRESHOLD) ); - } - - ApplyStickDeadZone( float(xstate.Gamepad.sThumbLX), float(xstate.Gamepad.sThumbLY), - deadZoneMode, 32767.f, float(XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE), - state.thumbSticks.leftX, state.thumbSticks.leftY ); - - ApplyStickDeadZone( float(xstate.Gamepad.sThumbRX), float(xstate.Gamepad.sThumbRY), - deadZoneMode, 32767.f, float(XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE), - state.thumbSticks.rightX, state.thumbSticks.rightY ); - - return; - } - } - - memset( &state, 0, sizeof(State) ); - } - - void GetCapabilities( int player, _Out_ Capabilities& caps ) - { - if ( !ThrottleRetry(player) ) - { - XINPUT_CAPABILITIES xcaps; - DWORD result = XInputGetCapabilities( DWORD(player), 0, &xcaps ); - if ( result == ERROR_DEVICE_NOT_CONNECTED ) - { - ClearSlot( player, GetTickCount64() ); - } - else - { - mConnected[ player ] = true; - - caps.connected = true; - caps.id = uint64_t( player ); - if ( xcaps.Type == XINPUT_DEVTYPE_GAMEPAD ) - { - static_assert(Capabilities::GAMEPAD == XINPUT_DEVSUBTYPE_GAMEPAD, "xinput.h mismatch"); -#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) - static_assert( XINPUT_DEVSUBTYPE_WHEEL == Capabilities::WHEEL, "xinput.h mismatch"); - static_assert( XINPUT_DEVSUBTYPE_ARCADE_STICK == Capabilities::ARCADE_STICK, "xinput.h mismatch"); - static_assert( XINPUT_DEVSUBTYPE_FLIGHT_STICK == Capabilities::FLIGHT_STICK, "xinput.h mismatch"); - static_assert( XINPUT_DEVSUBTYPE_DANCE_PAD == Capabilities::DANCE_PAD, "xinput.h mismatch"); - static_assert( XINPUT_DEVSUBTYPE_GUITAR == Capabilities::GUITAR, "xinput.h mismatch"); - static_assert( XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE == Capabilities::GUITAR_ALTERNATE, "xinput.h mismatch"); - static_assert( XINPUT_DEVSUBTYPE_DRUM_KIT == Capabilities::DRUM_KIT, "xinput.h mismatch"); - static_assert( XINPUT_DEVSUBTYPE_GUITAR_BASS == Capabilities::GUITAR_BASS, "xinput.h mismatch"); - static_assert( XINPUT_DEVSUBTYPE_ARCADE_PAD == Capabilities::ARCADE_PAD, "xinput.h mismatch"); -#endif - - caps.gamepadType = Capabilities::Type(xcaps.SubType); - } - - return; - } - } - - memset( &caps, 0, sizeof(Capabilities) ); - } - - bool SetVibration( int player, float leftMotor, float rightMotor, float leftTrigger, float rightTrigger ) - { - if ( ThrottleRetry(player) ) - { - return false; - } - - // XInput does not provide a way to set the left/right trigger impulse motors on the Xbox One Controller, - // and these motors are not present on the Xbox 360 Common Controller - UNREFERENCED_PARAMETER(leftTrigger); - UNREFERENCED_PARAMETER(rightTrigger); - -#if (_WIN32_WINNT < _WIN32_WINNT_WIN8) - mLeftMotor[ player ] = leftMotor; - mRightMotor[ player ] = rightMotor; - - if ( mSuspended ) - return mConnected[ player ]; -#endif - - XINPUT_VIBRATION xvibration; - xvibration.wLeftMotorSpeed = WORD( leftMotor * 0xFFFF ); - xvibration.wRightMotorSpeed = WORD( rightMotor * 0xFFFF ); - DWORD result = XInputSetState( DWORD(player), &xvibration ); - if ( result == ERROR_DEVICE_NOT_CONNECTED ) - { - ClearSlot( player, GetTickCount64() ); - return false; - } - else - { - mConnected[ player ] = true; - return (result == ERROR_SUCCESS); - } - } - - void Suspend() - { -#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) - XInputEnable( FALSE ); -#else - // For XInput 9.1.0, we have to emulate the behavior of XInputEnable( FALSE ) - if ( !mSuspended ) - { - for( size_t j = 0; j < XUSER_MAX_COUNT; ++j ) - { - if ( mConnected[ j ] ) - { - XINPUT_VIBRATION xvibration; - xvibration.wLeftMotorSpeed = xvibration.wRightMotorSpeed = 0; - (void)XInputSetState( DWORD(j), &xvibration ); - } - } - - mSuspended = true; - } -#endif - } - - void Resume() - { -#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) - XInputEnable( TRUE ); -#else - // For XInput 9.1.0, we have to emulate the behavior of XInputEnable( TRUE ) - if ( mSuspended ) - { - for( int j = 0; j < XUSER_MAX_COUNT; ++j ) - { - if ( mConnected[ j ] ) - { - XINPUT_VIBRATION xvibration; - xvibration.wLeftMotorSpeed = WORD( mLeftMotor[ j ] * 0xFFFF ); - xvibration.wRightMotorSpeed = WORD( mRightMotor[ j ] * 0xFFFF ); - DWORD result = XInputSetState( DWORD(j), &xvibration ); - if ( result == ERROR_DEVICE_NOT_CONNECTED ) - { - ClearSlot( j, GetTickCount64() ); - } - } - } - - mSuspended = false; - } -#endif - } - -private: - bool mConnected[ XUSER_MAX_COUNT ]; - ULONGLONG mLastReadTime[ XUSER_MAX_COUNT ]; - -#if (_WIN32_WINNT < _WIN32_WINNT_WIN8) - // Variables for emulating XInputEnable on XInput 9.1.0 - float mLeftMotor[ XUSER_MAX_COUNT ]; - float mRightMotor[ XUSER_MAX_COUNT ]; - bool mSuspended; -#endif - - static GamePad::Impl* s_gamePad; - - bool ThrottleRetry( int player ) - { - // This function minimizes a potential performance issue with XInput on Windows when - // checking a disconnected controller slot which requires device enumeration. - // This throttling keeps checks for newly connected gamepads to about once a second - - if ( ( player < 0 ) || ( player >= XUSER_MAX_COUNT ) ) - return true; - - if ( mConnected[ player ] ) - return false; - - ULONGLONG time = GetTickCount64(); - - for( size_t j = 0; j < XUSER_MAX_COUNT; ++j ) - { - if ( !mConnected[j] ) - { - LONGLONG delta = time - mLastReadTime[j]; - - LONGLONG interval = 1000; - if ( (int)j != player ) - interval /= 4; - - if ( (delta >= 0) && (delta < interval) ) - return true; - } - } - - return false; - } - - void ClearSlot( int player, ULONGLONG time ) - { - mConnected[ player ] = false; - mLastReadTime[ player ] = time; -#if (_WIN32_WINNT < _WIN32_WINNT_WIN8) - mLeftMotor[ player ] = mRightMotor[ player ] = 0.f; -#endif - } -}; - -GamePad::Impl* GamePad::Impl::s_gamePad = nullptr; - -#endif - - -// Public constructor. -GamePad::GamePad() - : pImpl( new Impl() ) -{ -} - - -// Move constructor. -GamePad::GamePad(GamePad&& moveFrom) - : pImpl(std::move(moveFrom.pImpl)) -{ -} - - -// Move assignment. -GamePad& GamePad::operator= (GamePad&& moveFrom) -{ - pImpl = std::move(moveFrom.pImpl); - return *this; -} - - -// Public destructor. -GamePad::~GamePad() -{ -} - - -GamePad::State GamePad::GetState(int player, DeadZone deadZoneMode) -{ - State state; - pImpl->GetState(player, state, deadZoneMode); - return state; -} - - -GamePad::Capabilities GamePad::GetCapabilities(int player) -{ - Capabilities caps; - pImpl->GetCapabilities(player, caps); - return caps; -} - - -bool GamePad::SetVibration( int player, float leftMotor, float rightMotor, float leftTrigger, float rightTrigger ) -{ - return pImpl->SetVibration( player, leftMotor, rightMotor, leftTrigger, rightTrigger ); -} - - -void GamePad::Suspend() -{ - pImpl->Suspend(); -} - - -void GamePad::Resume() -{ - pImpl->Resume(); -} - - -//====================================================================================== -// ButtonStateTracker -//====================================================================================== - -#define UPDATE_BUTTON_STATE(field) field = static_cast( ( !!state.buttons.field ) | ( ( !!state.buttons.field ^ !!lastState.buttons.field ) << 1 ) ); - -void GamePad::ButtonStateTracker::Update( const GamePad::State& state ) -{ - UPDATE_BUTTON_STATE(a); - - assert( ( !state.buttons.a && !lastState.buttons.a ) == ( a == UP ) ); - assert( ( state.buttons.a && lastState.buttons.a ) == ( a == HELD ) ); - assert( ( !state.buttons.a && lastState.buttons.a ) == ( a == RELEASED ) ); - assert( ( state.buttons.a && !lastState.buttons.a ) == ( a == PRESSED ) ); - - UPDATE_BUTTON_STATE(b); - UPDATE_BUTTON_STATE(x); - UPDATE_BUTTON_STATE(y); - - UPDATE_BUTTON_STATE(leftStick); - UPDATE_BUTTON_STATE(rightStick); - - UPDATE_BUTTON_STATE(leftShoulder); - UPDATE_BUTTON_STATE(rightShoulder); - - UPDATE_BUTTON_STATE(back); - UPDATE_BUTTON_STATE(start); - - dpadUp = static_cast( ( !!state.dpad.up ) | ( ( !!state.dpad.up ^ !!lastState.dpad.up ) << 1 ) ); - dpadDown = static_cast( ( !!state.dpad.down ) | ( ( !!state.dpad.down ^ !!lastState.dpad.down ) << 1 ) ); - dpadLeft = static_cast( ( !!state.dpad.left ) | ( ( !!state.dpad.left ^ !!lastState.dpad.left ) << 1 ) ); - dpadRight = static_cast( ( !!state.dpad.right ) | ( ( !!state.dpad.right ^ !!lastState.dpad.right ) << 1 ) ); - - assert( ( !state.dpad.up && !lastState.dpad.up ) == ( dpadUp == UP ) ); - assert( ( state.dpad.up && lastState.dpad.up ) == ( dpadUp == HELD ) ); - assert( ( !state.dpad.up && lastState.dpad.up ) == ( dpadUp == RELEASED ) ); - assert( ( state.dpad.up && !lastState.dpad.up ) == ( dpadUp == PRESSED ) ); - - lastState = state; -} - -#undef UPDATE_BUTTON_STATE - - -void GamePad::ButtonStateTracker::Reset() -{ - memset( this, 0, sizeof(ButtonStateTracker) ); -}