//----------------------------------------------------------------------------- // 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 ); } } } }
// Create a force feedback effect handle and downloads the effect. Parameters are self-explanatory. bool CreateEffectHandle( HWND hWnd, LPDIRECTINPUTDEVICE8 lpDirectInputDevice, LPDIRECTINPUTEFFECT &pDIEffect, BYTE bRumbleTyp, long lStrength ) { if( pDIEffect ) ReleaseEffect( pDIEffect ); if( !lpDirectInputDevice || bRumbleTyp == RUMBLE_DIRECT ) return false; DWORD nAxes = 0; DWORD rgdwAxes[] = { DIJOFS_X, DIJOFS_Y }; HRESULT hResult; // count the FF - axes of the joystick lpDirectInputDevice->EnumObjects( EnumCountFFAxes, &nAxes, DIDFT_FFACTUATOR | DIDFT_AXIS ); if( nAxes == 0 ) return false; nAxes = min( nAxes, 2 ); // Must be unaquired for setting stuff like Co-op Level hResult = lpDirectInputDevice->Unacquire(); //FF Requires EXCLUSIVE LEVEL, took me hours to find the reason why it wasnt working hResult = lpDirectInputDevice->SetCooperativeLevel( hWnd, DIB_FF ); // fail if we can't set coop level --rabid if (hResult != DI_OK) { DebugWriteA("CreateEffectHandle: couldn't set coop level: %08X\n", hResult); return false; } // Since we will be playing force feedback effects, we should disable the // auto-centering spring. DIPROPDWORD dipdw; dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwObj = 0; dipdw.diph.dwHow = DIPH_DEVICE; dipdw.dwData = FALSE; hResult = lpDirectInputDevice->SetProperty( DIPROP_AUTOCENTER, &dipdw.diph ); long rglDirection[] = { 1, 1 }; LPGUID EffectGuid; DIEFFECT eff; ZeroMemory( &eff, sizeof(eff) ); eff.dwSize = sizeof(DIEFFECT); eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; eff.dwGain = lStrength * 100; eff.dwTriggerButton = DIEB_NOTRIGGER; eff.dwTriggerRepeatInterval = 0; eff.cAxes = nAxes; //Number of Axes eff.rgdwAxes = rgdwAxes; eff.rglDirection = rglDirection; eff.lpEnvelope = NULL; eff.dwStartDelay = 0; DICONSTANTFORCE cf; DIRAMPFORCE rf; DIPERIODIC pf; switch( bRumbleTyp ) { case RUMBLE_CONSTANT: EffectGuid = (GUID*)&GUID_ConstantForce; eff.dwDuration = 150000; // microseconds eff.dwSamplePeriod = 0; eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); eff.lpvTypeSpecificParams = &cf; cf.lMagnitude = 10000; break; case RUMBLE_RAMP: EffectGuid = (GUID*)&GUID_RampForce; eff.dwDuration = 300000; // microseconds eff.dwSamplePeriod = 0; eff.cbTypeSpecificParams = sizeof(DIRAMPFORCE); eff.lpvTypeSpecificParams = &rf; rf.lStart = 10000; rf.lEnd = 2000; break; case RUMBLE_CONDITION: case RUMBLE_PERIODIC: EffectGuid = (GUID*)&GUID_Sine; eff.dwDuration = 150000; // microseconds eff.dwSamplePeriod = 0; eff.cbTypeSpecificParams = sizeof(DIPERIODIC); eff.lpvTypeSpecificParams = &pf; pf.dwMagnitude = 10000; pf.lOffset = 0; pf.dwPhase = 0; pf.dwPeriod = 2000; break; case RUMBLE_NONE: case RUMBLE_CUSTOM: default: return false; } hResult = lpDirectInputDevice->CreateEffect( *EffectGuid, &eff, &pDIEffect, NULL ); if (hResult == DI_OK) { hResult = lpDirectInputDevice->Acquire(); hResult = pDIEffect->Download(); } else { DebugWriteA("CreateEffectHandle: didn't CreateEffect: %08X\n", hResult); } return SUCCEEDED( hResult ); }