From 39ed87570bdb2f86969d4be821c94b722dc71179 Mon Sep 17 00:00:00 2001 From: Joe Ludwig Date: Wed, 26 Jun 2013 15:22:04 -0700 Subject: First version of the SOurce SDK 2013 --- mp/src/game/client/in_forcefeedback.cpp | 834 ++++++++++++++++++++++++++++++++ 1 file changed, 834 insertions(+) create mode 100644 mp/src/game/client/in_forcefeedback.cpp (limited to 'mp/src/game/client/in_forcefeedback.cpp') diff --git a/mp/src/game/client/in_forcefeedback.cpp b/mp/src/game/client/in_forcefeedback.cpp new file mode 100644 index 00000000..f55b981d --- /dev/null +++ b/mp/src/game/client/in_forcefeedback.cpp @@ -0,0 +1,834 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Force feeback OS level handlers +// +//============================================================================= +#include +#include "basehandle.h" +#include "utlvector.h" +#include "usercmd.h" +#include "cdll_client_int.h" +#include "cdll_util.h" +#include "input.h" +#include "convar.h" +#include "tier0/icommandline.h" +#include "forcefeedback.h" +#include "filesystem.h" + +#define DIRECTINPUT_VERSION 0x0800 + +#include "dinput.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +static ConVar ff_autocenter( "ff_autocenter", "1", FCVAR_ARCHIVE, "Enable auto-centering of forcefeedback joystick." ); + +struct ForceFeedbackParams_t +{ + bool m_bForceFeedbackAvailable; + + LPDIRECTINPUT8 m_pIInput; + LPDIRECTINPUTDEVICE8 m_pIJoystick; + bool m_bPaused; +}; + +typedef CUtlVector< LPDIRECTINPUTEFFECT > vecEffectPtr_t; + +class EffectMap_t +{ +public: + FORCEFEEDBACK_t effect; + char const *effectfile; + vecEffectPtr_t *pVecEffectPtr; + bool m_bDownloaded; +}; + +static EffectMap_t g_EffectMap[] = +{ + { FORCE_FEEDBACK_SHOT_SINGLE, "scripts/forcefeedback/singleshot.ffe" }, + { FORCE_FEEDBACK_SHOT_DOUBLE, "scripts/forcefeedback/doubleshot.ffe" }, + { FORCE_FEEDBACK_TAKEDAMAGE, "scripts/forcefeedback/takedamage.ffe" }, + { FORCE_FEEDBACK_SCREENSHAKE, "scripts/forcefeedback/screenshake.ffe" }, + { FORCE_FEEDBACK_SKIDDING, "scripts/forcefeedback/skidding.ffe" }, + { FORCE_FEEDBACK_BREAKING, "scripts/forcefeedback/breaking.ffe" }, +}; + +static void InitEffectMap() +{ + int c = ARRAYSIZE( g_EffectMap ); + for ( int i = 0; i < c; ++i ) + { + g_EffectMap[ i ].pVecEffectPtr = new vecEffectPtr_t(); + } +} +static void ShutdownEffectMap() +{ + int c = ARRAYSIZE( g_EffectMap ); + for ( int i = 0; i < c; ++i ) + { + if ( g_EffectMap[ i ].pVecEffectPtr ) + { + g_EffectMap[ i ].pVecEffectPtr->RemoveAll(); + delete g_EffectMap[ i ].pVecEffectPtr; + } + g_EffectMap[ i ].pVecEffectPtr = NULL; + } +} + +static void ReportCap( int flags, int bits, char const *desc ) +{ + if ( flags & bits ) + { + DevMsg( "%s\n", desc ); + } +} + +static void ReportDevType( DWORD devType ) +{ + byte baseType = GET_DIDEVICE_TYPE( devType ); + byte subType = GET_DIDEVICE_SUBTYPE( devType ); + + switch ( baseType ) + { + default: + DevMsg( "unknown type\n" ); + break; + case DI8DEVTYPE_DEVICE: + DevMsg( "DEVICE\n" ); + break; + case DI8DEVTYPE_MOUSE: + DevMsg( "MOUSE\n" ); + switch ( subType ) + { + default: + break; + case DI8DEVTYPEMOUSE_UNKNOWN: + DevMsg( "DI8DEVTYPEMOUSE_UNKNOWN\n" ); + break; + case DI8DEVTYPEMOUSE_TRADITIONAL: + DevMsg( "DI8DEVTYPEMOUSE_TRADITIONAL\n" ); + break; + case DI8DEVTYPEMOUSE_FINGERSTICK: + DevMsg( "DI8DEVTYPEMOUSE_FINGERSTICK\n" ); + break; + case DI8DEVTYPEMOUSE_TOUCHPAD: + DevMsg( "DI8DEVTYPEMOUSE_TOUCHPAD\n" ); + break; + case DI8DEVTYPEMOUSE_TRACKBALL: + DevMsg( "DI8DEVTYPEMOUSE_TRACKBALL\n" ); + break; + case DI8DEVTYPEMOUSE_ABSOLUTE: + DevMsg( "DI8DEVTYPEMOUSE_ABSOLUTE\n" ); + break; + } + break; + case DI8DEVTYPE_KEYBOARD: + DevMsg( "KEYBOARD\n" ); + switch ( subType ) + { + default: + break; + case DI8DEVTYPEKEYBOARD_UNKNOWN: + DevMsg( "DI8DEVTYPEKEYBOARD_UNKNOWN\n" ); + break; + case DI8DEVTYPEKEYBOARD_PCXT: + DevMsg( "DI8DEVTYPEKEYBOARD_PCXT\n" ); + break; + case DI8DEVTYPEKEYBOARD_OLIVETTI: + DevMsg( "DI8DEVTYPEKEYBOARD_OLIVETTI\n" ); + break; + case DI8DEVTYPEKEYBOARD_PCAT: + DevMsg( "DI8DEVTYPEKEYBOARD_PCAT\n" ); + break; + case DI8DEVTYPEKEYBOARD_PCENH: + DevMsg( "DI8DEVTYPEKEYBOARD_PCENH:\n" ); + break; + case DI8DEVTYPEKEYBOARD_NOKIA1050: + DevMsg( "DI8DEVTYPEKEYBOARD_NOKIA1050\n" ); + break; + case DI8DEVTYPEKEYBOARD_NOKIA9140: + DevMsg( "DI8DEVTYPEKEYBOARD_NOKIA9140\n" ); + break; + case DI8DEVTYPEKEYBOARD_NEC98: + DevMsg( "DI8DEVTYPEKEYBOARD_NEC98\n" ); + break; + case DI8DEVTYPEKEYBOARD_NEC98LAPTOP: + DevMsg( "DI8DEVTYPEKEYBOARD_NEC98LAPTOP\n" ); + break; + case DI8DEVTYPEKEYBOARD_NEC98106: + DevMsg( "DI8DEVTYPEKEYBOARD_NEC98106\n" ); + break; + case DI8DEVTYPEKEYBOARD_JAPAN106: + DevMsg( "DI8DEVTYPEKEYBOARD_JAPAN106\n" ); + break; + case DI8DEVTYPEKEYBOARD_JAPANAX: + DevMsg( "DI8DEVTYPEKEYBOARD_JAPANAX\n" ); + break; + case DI8DEVTYPEKEYBOARD_J3100: + DevMsg( "DI8DEVTYPEKEYBOARD_J3100\n" ); + break; + } + break; + case DI8DEVTYPE_JOYSTICK: + DevMsg( "JOYSTICK\n" ); + switch ( subType ) + { + default: + break; + case DI8DEVTYPEJOYSTICK_LIMITED : + DevMsg( "DI8DEVTYPEJOYSTICK_LIMITED\n" ); + break; + case DI8DEVTYPEJOYSTICK_STANDARD: + DevMsg( "DI8DEVTYPEJOYSTICK_STANDARD\n" ); + break; + } + break; + case DI8DEVTYPE_GAMEPAD: + DevMsg( "GAMEPAD\n" ); + switch ( subType ) + { + default: + break; + case DI8DEVTYPEGAMEPAD_LIMITED: + DevMsg( "DI8DEVTYPEGAMEPAD_LIMITED\n" ); + break; + case DI8DEVTYPEGAMEPAD_STANDARD: + DevMsg( "DI8DEVTYPEGAMEPAD_STANDARD\n" ); + break; + case DI8DEVTYPEGAMEPAD_TILT: + DevMsg( "DI8DEVTYPEGAMEPAD_TILT\n" ); + break; + } + break; + case DI8DEVTYPE_DRIVING: + DevMsg( "DRIVING\n" ); + switch ( subType ) + { + default: + break; + case DI8DEVTYPEDRIVING_LIMITED: + DevMsg( "DI8DEVTYPEDRIVING_LIMITED\n" ); + break; + case DI8DEVTYPEDRIVING_COMBINEDPEDALS: + DevMsg( "DI8DEVTYPEDRIVING_COMBINEDPEDALS\n" ); + break; + case DI8DEVTYPEDRIVING_DUALPEDALS: + DevMsg( "DI8DEVTYPEDRIVING_DUALPEDALS\n" ); + break; + case DI8DEVTYPEDRIVING_THREEPEDALS: + DevMsg( "DI8DEVTYPEDRIVING_THREEPEDALS\n" ); + break; + case DI8DEVTYPEDRIVING_HANDHELD: + DevMsg( "DI8DEVTYPEDRIVING_HANDHELD\n" ); + break; + } + break; + case DI8DEVTYPE_FLIGHT: + DevMsg( "FLIGHT\n" ); + switch ( subType ) + { + default: + break; + case DI8DEVTYPEFLIGHT_LIMITED: + DevMsg( "DI8DEVTYPEFLIGHT_LIMITED\n" ); + break; + case DI8DEVTYPEFLIGHT_STICK: + DevMsg( "DI8DEVTYPEFLIGHT_STICK\n" ); + break; + case DI8DEVTYPEFLIGHT_YOKE: + DevMsg( "DI8DEVTYPEFLIGHT_YOKE\n" ); + break; + case DI8DEVTYPEFLIGHT_RC: + DevMsg( "DI8DEVTYPEFLIGHT_RC\n" ); + break; + } + break; + case DI8DEVTYPE_1STPERSON: + DevMsg( "1STPERSON\n" ); + switch ( subType ) + { + default: + break; + case DI8DEVTYPE1STPERSON_LIMITED: + DevMsg( "DI8DEVTYPE1STPERSON_LIMITED\n" ); + break; + case DI8DEVTYPE1STPERSON_UNKNOWN: + DevMsg( "DI8DEVTYPE1STPERSON_UNKNOWN\n" ); + break; + case DI8DEVTYPE1STPERSON_SIXDOF: + DevMsg( "DI8DEVTYPE1STPERSON_SIXDOF\n" ); + break; + case DI8DEVTYPE1STPERSON_SHOOTER: + DevMsg( "DI8DEVTYPE1STPERSON_SHOOTER\n" ); + break; + } + break; + case DI8DEVTYPE_DEVICECTRL: + DevMsg( "DEVICECTRL\n" ); + switch ( subType ) + { + default: + break; + case DI8DEVTYPEDEVICECTRL_UNKNOWN: + DevMsg( "DI8DEVTYPEDEVICECTRL_UNKNOWN\n" ); + break; + case DI8DEVTYPEDEVICECTRL_COMMSSELECTION: + DevMsg( "DI8DEVTYPEDEVICECTRL_COMMSSELECTION\n" ); + break; + case DI8DEVTYPEDEVICECTRL_COMMSSELECTION_HARDWIRED: + DevMsg( "DI8DEVTYPEDEVICECTRL_COMMSSELECTION_HARDWIRED\n" ); + break; + } + break; + case DI8DEVTYPE_SCREENPOINTER: + DevMsg( "SCREENPOINTER\n" ); + switch ( subType ) + { + default: + break; + case DI8DEVTYPESCREENPTR_UNKNOWN: + DevMsg( "DI8DEVTYPESCREENPTR_UNKNOWN\n" ); + break; + case DI8DEVTYPESCREENPTR_LIGHTGUN: + DevMsg( "DI8DEVTYPESCREENPTR_LIGHTGUN\n" ); + break; + case DI8DEVTYPESCREENPTR_LIGHTPEN: + DevMsg( "DI8DEVTYPESCREENPTR_LIGHTPEN\n" ); + break; + case DI8DEVTYPESCREENPTR_TOUCH: + DevMsg( "DI8DEVTYPESCREENPTR_TOUCH\n" ); + break; + } + break; + case DI8DEVTYPE_REMOTE: + DevMsg( "REMOTE\n" ); + switch ( subType ) + { + default: + break; + case DI8DEVTYPEREMOTE_UNKNOWN: + DevMsg( "DI8DEVTYPEREMOTE_UNKNOWN\n" ); + break; + } + break; + case DI8DEVTYPE_SUPPLEMENTAL: + DevMsg( "SUPPLEMENTAL\n" ); + switch ( subType ) + { + default: + break; + case DI8DEVTYPESUPPLEMENTAL_UNKNOWN: + DevMsg( "DI8DEVTYPESUPPLEMENTAL_UNKNOWN\n" ); + break; + case DI8DEVTYPESUPPLEMENTAL_2NDHANDCONTROLLER: + DevMsg( "DI8DEVTYPESUPPLEMENTAL_2NDHANDCONTROLLER\n" ); + break; + case DI8DEVTYPESUPPLEMENTAL_HEADTRACKER: + DevMsg( "DI8DEVTYPESUPPLEMENTAL_HEADTRACKER\n" ); + break; + case DI8DEVTYPESUPPLEMENTAL_HANDTRACKER: + DevMsg( "DI8DEVTYPESUPPLEMENTAL_HANDTRACKER\n" ); + break; + case DI8DEVTYPESUPPLEMENTAL_SHIFTSTICKGATE: + DevMsg( "DI8DEVTYPESUPPLEMENTAL_SHIFTSTICKGATE\n" ); + break; + case DI8DEVTYPESUPPLEMENTAL_SHIFTER: + DevMsg( "DI8DEVTYPESUPPLEMENTAL_SHIFTER\n" ); + break; + case DI8DEVTYPESUPPLEMENTAL_THROTTLE: + DevMsg( "DI8DEVTYPESUPPLEMENTAL_THROTTLE\n" ); + break; + case DI8DEVTYPESUPPLEMENTAL_SPLITTHROTTLE: + DevMsg( "DI8DEVTYPESUPPLEMENTAL_SPLITTHROTTLE\n" ); + break; + case DI8DEVTYPESUPPLEMENTAL_COMBINEDPEDALS: + DevMsg( "DI8DEVTYPESUPPLEMENTAL_COMBINEDPEDALS\n" ); + break; + case DI8DEVTYPESUPPLEMENTAL_DUALPEDALS: + DevMsg( "DI8DEVTYPESUPPLEMENTAL_DUALPEDALS\n" ); + break; + case DI8DEVTYPESUPPLEMENTAL_THREEPEDALS: + DevMsg( "DI8DEVTYPESUPPLEMENTAL_THREEPEDALS\n" ); + break; + case DI8DEVTYPESUPPLEMENTAL_RUDDERPEDALS: + DevMsg( "DI8DEVTYPESUPPLEMENTAL_RUDDERPEDALS\n" ); + break; + } + break; + } +} + +static void DescribeFFDevice( const DIDEVCAPS& caps ) +{ + ReportCap( caps.dwFlags, DIDC_ALIAS, " DIDC_ALIAS" ); + ReportCap( caps.dwFlags, DIDC_ATTACHED, " device is attached" ); + ReportCap( caps.dwFlags, DIDC_DEADBAND, " device supports deadband" ); + //ReportCap( caps.dwFlags, DIDC_EMULATED, " device is emulated" ); + ReportCap( caps.dwFlags, DIDC_FFFADE, " device supports fade" ); + ReportCap( caps.dwFlags, DIDC_FFATTACK, " device supports attack" ); + ReportCap( caps.dwFlags, DIDC_HIDDEN, " DIDC_HIDDEN" ); + ReportCap( caps.dwFlags, DIDC_PHANTOM, " DIDC_PHANTOM" ); + ReportCap( caps.dwFlags, DIDC_POLLEDDATAFORMAT, " device using polled data format" ); + ReportCap( caps.dwFlags, DIDC_POLLEDDEVICE, " device is polled" ); + ReportCap( caps.dwFlags, DIDC_POSNEGCOEFFICIENTS, " device supports two coefficient values for conditions" ); + ReportCap( caps.dwFlags, DIDC_POSNEGSATURATION, " DIDC_POSNEGSATURATION" ); + ReportCap( caps.dwFlags, DIDC_SATURATION, " device supports saturation" ); + ReportCap( caps.dwFlags, DIDC_STARTDELAY, " device supports start delay" ); + + ReportDevType( caps.dwDevType ); + + DevMsg( " %u buttons\n", caps.dwButtons ); + DevMsg( " %u axes\n", caps.dwAxes ); + DevMsg( " %u POVs\n", caps.dwPOVs ); + + DevMsg( " %.1f msec FF sample period\n", (float)caps.dwFFSamplePeriod/1000.0f ); + DevMsg( " %.1f msec FF min time resolution period\n", (float)caps.dwFFMinTimeResolution/1000.0f ); +} + +struct LoadEffectContext_t +{ + LPDIRECTINPUTDEVICE8 device; + EffectMap_t *map; +}; + +static BOOL CALLBACK EnumEffectsInFileProc(LPCDIFILEEFFECT lpdife, LPVOID pvRef) + +{ + LoadEffectContext_t *ctx = ( LoadEffectContext_t * )pvRef; + + EffectMap_t *map = ctx->map; + + + vecEffectPtr_t *vecPtr = map->pVecEffectPtr; + Assert( vecPtr ); + + int idx = vecPtr->AddToTail( NULL ); + + HRESULT hr; + hr = ctx->device->CreateEffect + ( + lpdife->GuidEffect, + lpdife->lpDiEffect, + &(*vecPtr)[ idx ], + NULL + ); + + if ( FAILED ( hr ) ) + { + // Error handling + Msg( "EnumEffectsInFileProc during effect loading for %s\n", map->effectfile ); + } + + return DIENUM_CONTINUE; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : device - +// &map - +// Output : static void +//----------------------------------------------------------------------------- +static void LoadEffectFile( LPDIRECTINPUTDEVICE8 device, EffectMap_t &map ) +{ + LoadEffectContext_t context; + context.device = device; + context.map = ↦ + + // Pull out of .gcf if needed + filesystem->GetLocalCopy( map.effectfile ); + + char fullpath[ 512 ]; + filesystem->GetLocalPath( map.effectfile, fullpath, sizeof( fullpath ) ); + + HRESULT hr = device->EnumEffectsInFile + ( fullpath, + EnumEffectsInFileProc, + (LPVOID)&context, + DIFEF_MODIFYIFNEEDED ); + + if ( FAILED( hr ) ) + { + Msg( "EnumEffectsInFile failed for %s\n", map.effectfile ); + } + +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : device - +// Output : static void +//----------------------------------------------------------------------------- +static void LoadEffectFiles( LPDIRECTINPUTDEVICE8 device ) +{ + int c = ARRAYSIZE( g_EffectMap ); + for ( int i = 0; i < c; ++i ) + { + EffectMap_t& map = g_EffectMap[ i ]; + + LoadEffectFile( device, map ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Init_ForceFeedback +//----------------------------------------------------------------------------- +void CInput::Init_ForceFeedback() +{ + // abort startup if user requests no joystick + if ( CommandLine()->FindParm("-noff" ) ) + { + return; + } + + Assert( !m_pFF ); + + m_pFF = new ForceFeedbackParams_t; + Assert( m_pFF ); + Q_memset( m_pFF, 0, sizeof( *m_pFF ) ); + + HRESULT hr = DirectInput8Create(GetModuleHandle(0), DIRECTINPUT_VERSION, + IID_IDirectInput8, (void**)&m_pFF->m_pIInput, NULL ); + + if ( FAILED( hr ) ) + { + return; + } + + hr = m_pFF->m_pIInput->CreateDevice(GUID_Joystick, &m_pFF->m_pIJoystick, NULL ); + if ( FAILED( hr ) ) + { + return; + } + + hr = m_pFF->m_pIJoystick->SetDataFormat(&c_dfDIJoystick2 ); + + if ( FAILED( hr ) ) + { + return; + } + + HWND mainWnd = (HWND)g_pEngineWindow->GetWindowHandle(); + + hr = m_pFF->m_pIJoystick->SetCooperativeLevel( mainWnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE ); + + if ( FAILED( hr ) ) + { + return; + } + + DIPROPDWORD dwd; + //The following code turns the center spring off + dwd.diph.dwSize = sizeof(DIPROPDWORD); + dwd.diph.dwHeaderSize = sizeof(DIPROPHEADER); + dwd.diph.dwObj = 0; + dwd.diph.dwHow = DIPH_DEVICE; + dwd.dwData = FALSE; + + if ( !ff_autocenter.GetBool() ) + { + hr = m_pFF->m_pIJoystick->SetProperty( DIPROP_AUTOCENTER, &dwd.diph ); + if ( FAILED( hr ) ) + { + return; + } + } + + // Acquire the device + hr = m_pFF->m_pIJoystick->Acquire(); + + if( FAILED( hr ) ) + { + return; + } + + DIDEVCAPS diDevCaps; + Q_memset( &diDevCaps, 0, sizeof( diDevCaps ) ); + diDevCaps.dwSize = sizeof( diDevCaps ); + + hr = m_pFF->m_pIJoystick->GetCapabilities( &diDevCaps ); + + if ( FAILED( hr ) ) + { + DevMsg( "GetCapabilities failed\n" ); + return; + } + + if ( !( diDevCaps.dwFlags & DIDC_FORCEFEEDBACK ) ) + { + // Doesn't support FF + return; + } + + DIDEVICEINSTANCE diDI; + Q_memset( &diDI, 0, sizeof( diDI ) ); + diDI.dwSize = sizeof( diDI ); + + hr = m_pFF->m_pIJoystick->GetDeviceInfo( &diDI ); + if ( FAILED( hr ) ) + { + DevMsg( "GetDeviceInfo failed\n" ); + return; + } + + DevMsg( "Forcefeedback device found:\n" ); + + //DevMsg( " device '%s'\n", diDI.tszInstanceName ); + DevMsg( " product '%s'\n", diDI.tszProductName ); + + DescribeFFDevice( diDevCaps ); + + InitEffectMap(); + + LoadEffectFiles( m_pFF->m_pIJoystick ); + + m_pFF->m_bForceFeedbackAvailable = true; +} + +//----------------------------------------------------------------------------- +// Purpose: Shutdown_ForceFeedback +//----------------------------------------------------------------------------- +void CInput::Shutdown_ForceFeedback() +{ + HRESULT hr; + + Assert( m_pFF ); + + if ( !m_pFF ) + { + return; + } + + if ( m_pFF->m_bForceFeedbackAvailable ) + { + m_pFF->m_bForceFeedbackAvailable = false; + + ShutdownEffectMap(); + + // Do cleanup + if ( m_pFF->m_pIJoystick ) + { + hr = m_pFF->m_pIJoystick->Unacquire(); + if ( FAILED( hr ) ) + { + DevMsg( "Forcefeedback Unacquire failed\n" ); + } + + hr = m_pFF->m_pIJoystick->Release(); + if ( FAILED( hr ) ) + { + DevMsg( "Forcefeedback Release failed\n" ); + } + } + + if ( m_pFF->m_pIInput ) + { + hr = m_pFF->m_pIInput->Release(); + if ( FAILED( hr ) ) + { + DevMsg( "DirectInput Release failed\n" ); + } + } + } + + delete m_pFF; + m_pFF = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CInput::ForceFeedback_Reaquire() +{ + if ( !m_pFF || !m_pFF->m_bForceFeedbackAvailable ) + return; + + HRESULT hr = m_pFF->m_pIJoystick->Acquire(); + if ( FAILED( hr ) ) + { + DevMsg( "ForceFeedback_Reaquire failed\n" ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Certain devices require polling periodically +//----------------------------------------------------------------------------- +void CInput::ForceFeedback_Think() +{ + if ( !m_pFF || !m_pFF->m_bForceFeedbackAvailable ) + return; + + HRESULT hr = m_pFF->m_pIJoystick->Poll(); + if ( FAILED( hr ) ) + { + if ( hr == DIERR_INPUTLOST || + hr == DIERR_NOTACQUIRED ) + { + ForceFeedback_Reaquire(); + } + } + +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CInput::ForceFeedback_StopAll() +{ + if ( !m_pFF || !m_pFF->m_bForceFeedbackAvailable ) + return; + + HRESULT hr = m_pFF->m_pIJoystick->SendForceFeedbackCommand( DISFFC_STOPALL ); + if ( hr == DIERR_INPUTLOST ) + { + ForceFeedback_Reaquire(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CInput::ForceFeedback_Pause() +{ + if ( !m_pFF || !m_pFF->m_bForceFeedbackAvailable ) + return; + + m_pFF->m_bPaused = true; + HRESULT hr = m_pFF->m_pIJoystick->SendForceFeedbackCommand( DISFFC_PAUSE ); + if ( hr == DIERR_INPUTLOST ) + { + ForceFeedback_Reaquire(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CInput::ForceFeedback_Resume() +{ + if ( !m_pFF || !m_pFF->m_bForceFeedbackAvailable ) + return; + + if ( !m_pFF->m_bPaused ) + return; + + m_pFF->m_bPaused = false; + HRESULT hr = m_pFF->m_pIJoystick->SendForceFeedbackCommand( DISFFC_CONTINUE ); + if ( hr == DIERR_INPUTLOST ) + { + ForceFeedback_Reaquire(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : effectnum - +// params - +//----------------------------------------------------------------------------- +void CInput::ForceFeedback_Start( int effectnum, const FFBaseParams_t& params ) +{ + if ( !m_pFF || !m_pFF->m_bForceFeedbackAvailable ) + return; + + // Unpause system... + if ( m_pFF->m_bPaused ) + { + ForceFeedback_Resume(); + } + + // look up the effect + FORCEFEEDBACK_t effect = (FORCEFEEDBACK_t)effectnum; + + if ( effect < 0 || effect >= NUM_FORCE_FEEDBACK_PRESETS ) + { + Assert( !"ForceFeedback_Start with bogus effectnum" ); + return; + } + + EffectMap_t *map = &g_EffectMap[ effectnum ]; + + vecEffectPtr_t *effects = map->pVecEffectPtr; + + + // Play the effects on the device + int c = effects->Count(); + for ( int i = 0; i < c; ++i ) + { + LPDIRECTINPUTEFFECT pEffect = (*effects)[ i ]; + + if ( !map->m_bDownloaded ) + { + pEffect->Download(); + map->m_bDownloaded = true; + } + + DWORD flags = DIEP_DIRECTION | DIEP_GAIN | DIEP_DURATION; + + LONG rglDirection[2] = { 0, 100 }; + + // Fill in parameters + DIEFFECT effect; + Q_memset( &effect, 0, sizeof( effect ) ); + effect.dwSize = sizeof( effect ); + effect.dwFlags = DIEFF_POLAR | DIEFF_OBJECTOFFSETS; + effect.rglDirection = rglDirection; + effect.cAxes = 2; + + HRESULT hr = pEffect->GetParameters( &effect, flags ); + if ( !FAILED( hr ) ) + { + // If params.m_flDuration == 0.0f then that means use the duration in the file + if ( params.m_flDuration <= -0.999f ) + { + effect.dwDuration = INFINITE; + } + else if( params.m_flDuration >= 0.001f ) + { + // Convert to microsseconds + effect.dwDuration = (DWORD)( params.m_flDuration * 1000000.0f ); + } + + effect.dwGain = params.m_flGain * 10000.0f; + effect.rglDirection[ 0 ] = 100.0f * params.m_flDirection; + effect.rglDirection[ 1 ] = 0; + + hr = pEffect->SetParameters( &effect, flags ); + if ( !FAILED( hr ) ) + { + pEffect->Start( 1, params.m_bSolo ? DIES_SOLO : 0 ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : effectnum - +//----------------------------------------------------------------------------- +void CInput::ForceFeedback_Stop( int effectnum ) +{ + if ( !m_pFF || !m_pFF->m_bForceFeedbackAvailable ) + return; + + + // look up the effect + FORCEFEEDBACK_t effect = (FORCEFEEDBACK_t)effectnum; + + if ( effect < 0 || effect >= NUM_FORCE_FEEDBACK_PRESETS ) + { + Assert( !"ForceFeedback_Stop with bogus effectnum" ); + return; + } + + EffectMap_t *map = &g_EffectMap[ effectnum ]; + + vecEffectPtr_t *effects = map->pVecEffectPtr; + + // Stop the effects on the device + int c = effects->Count(); + for ( int i = 0; i < c; ++i ) + { + LPDIRECTINPUTEFFECT pEffect = (*effects)[ i ]; + pEffect->Stop(); + } +} \ No newline at end of file -- cgit v1.2.3