00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "Win32/Win32ForceFeedback.h"
00024 #include "OISException.h"
00025 #include <Math.h>
00026
00027 #if defined (_DEBUG)
00028 #include <sstream>
00029 #endif
00030
00031 using namespace OIS;
00032
00033
00034 Win32ForceFeedback::Win32ForceFeedback(IDirectInputDevice8* joy) :
00035 mHandles(0), mJoyStick(joy)
00036 {
00037 }
00038
00039
00040 Win32ForceFeedback::~Win32ForceFeedback()
00041 {
00042
00043 for(EffectList::iterator i = mEffectList.begin(); i != mEffectList.end(); ++i )
00044 {
00045 LPDIRECTINPUTEFFECT dxEffect = i->second;
00046 if( dxEffect )
00047 dxEffect->Unload();
00048 }
00049
00050 mEffectList.clear();
00051 }
00052
00053
00054 void Win32ForceFeedback::upload( const Effect* effect )
00055 {
00056 switch( effect->force )
00057 {
00058 case OIS::Effect::ConstantForce: _updateConstantEffect(effect); break;
00059 case OIS::Effect::RampForce: _updateRampEffect(effect); break;
00060 case OIS::Effect::PeriodicForce: _updatePeriodicEffect(effect); break;
00061 case OIS::Effect::ConditionalForce: _updateConditionalEffect(effect); break;
00062
00063 default: OIS_EXCEPT(E_NotImplemented, "Requested Force not Implemented yet, sorry!"); break;
00064 }
00065 }
00066
00067
00068 void Win32ForceFeedback::modify( const Effect* eff )
00069 {
00070
00071 upload(eff);
00072 }
00073
00074
00075 void Win32ForceFeedback::remove( const Effect* eff )
00076 {
00077
00078 EffectList::iterator i = mEffectList.find(eff->_handle);
00079 if( i != mEffectList.end() )
00080 {
00081 LPDIRECTINPUTEFFECT dxEffect = i->second;
00082 if( dxEffect )
00083 {
00084 dxEffect->Stop();
00085
00086
00087 if( SUCCEEDED(dxEffect->Unload()) )
00088 mEffectList.erase(i);
00089 }
00090 else
00091 mEffectList.erase(i);
00092 }
00093 }
00094
00095
00096 void Win32ForceFeedback::setMasterGain( float level )
00097 {
00098
00099 int gain_level = (int)(10000.0f * level);
00100
00101 if( gain_level > 10000 )
00102 gain_level = 10000;
00103 else if( gain_level < 0 )
00104 gain_level = 0;
00105
00106 DIPROPDWORD DIPropGain;
00107 DIPropGain.diph.dwSize = sizeof(DIPropGain);
00108 DIPropGain.diph.dwHeaderSize = sizeof(DIPROPHEADER);
00109 DIPropGain.diph.dwObj = 0;
00110 DIPropGain.diph.dwHow = DIPH_DEVICE;
00111 DIPropGain.dwData = gain_level;
00112
00113 mJoyStick->SetProperty(DIPROP_FFGAIN, &DIPropGain.diph);
00114 }
00115
00116
00117 void Win32ForceFeedback::setAutoCenterMode( bool auto_on )
00118 {
00119
00120 DIPROPDWORD DIPropAutoCenter;
00121 DIPropAutoCenter.diph.dwSize = sizeof(DIPropAutoCenter);
00122 DIPropAutoCenter.diph.dwHeaderSize = sizeof(DIPROPHEADER);
00123 DIPropAutoCenter.diph.dwObj = 0;
00124 DIPropAutoCenter.diph.dwHow = DIPH_DEVICE;
00125 DIPropAutoCenter.dwData = auto_on;
00126
00127
00128 mJoyStick->SetProperty(DIPROP_AUTOCENTER, &DIPropAutoCenter.diph);
00129 }
00130
00131
00132 void Win32ForceFeedback::_updateConstantEffect( const Effect* effect )
00133 {
00134 DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y };
00135 LONG rglDirection[2] = { 0, 0 };
00136 DICONSTANTFORCE cf;
00137 DIEFFECT diEffect;
00138
00139
00140
00141 cf.lMagnitude = static_cast<ConstantEffect*>(effect->getForceEffect())->level;
00142
00143 _setCommonProperties(&diEffect, rgdwAxes, rglDirection, sizeof(DICONSTANTFORCE), &cf, effect);
00144 _upload(GUID_ConstantForce, &diEffect, effect);
00145 }
00146
00147
00148 void Win32ForceFeedback::_updateRampEffect( const Effect* effect )
00149 {
00150 DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y };
00151 LONG rglDirection[2] = { 0, 0 };
00152 DIRAMPFORCE rf;
00153 DIEFFECT diEffect;
00154
00155
00156 rf.lStart = static_cast<RampEffect*>(effect->getForceEffect())->startLevel;
00157 rf.lEnd = static_cast<RampEffect*>(effect->getForceEffect())->endLevel;
00158
00159 _setCommonProperties(&diEffect, rgdwAxes, rglDirection, sizeof(DIRAMPFORCE), &rf, effect);
00160 _upload(GUID_RampForce, &diEffect, effect);
00161 }
00162
00163
00164 void Win32ForceFeedback::_updatePeriodicEffect( const Effect* effect )
00165 {
00166 DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y };
00167 LONG rglDirection[2] = { 0, 0 };
00168 DIPERIODIC pf;
00169 DIEFFECT diEffect;
00170
00171
00172 pf.dwMagnitude = static_cast<PeriodicEffect*>(effect->getForceEffect())->magnitude;
00173 pf.lOffset = static_cast<PeriodicEffect*>(effect->getForceEffect())->offset;
00174 pf.dwPhase = static_cast<PeriodicEffect*>(effect->getForceEffect())->phase;
00175 pf.dwPeriod = static_cast<PeriodicEffect*>(effect->getForceEffect())->period;
00176
00177 _setCommonProperties(&diEffect, rgdwAxes, rglDirection, sizeof(DIPERIODIC), &pf, effect);
00178
00179 switch( effect->type )
00180 {
00181 case OIS::Effect::Square: _upload(GUID_Square, &diEffect, effect); break;
00182 case OIS::Effect::Triangle: _upload(GUID_Triangle, &diEffect, effect); break;
00183 case OIS::Effect::Sine: _upload(GUID_Sine, &diEffect, effect); break;
00184 case OIS::Effect::SawToothUp: _upload(GUID_SawtoothUp, &diEffect, effect); break;
00185 case OIS::Effect::SawToothDown: _upload(GUID_SawtoothDown, &diEffect, effect); break;
00186 default: break;
00187 }
00188 }
00189
00190
00191 void Win32ForceFeedback::_updateConditionalEffect( const Effect* effect )
00192 {
00193 DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y };
00194 LONG rglDirection[2] = { 0, 0 };
00195 DICONDITION cf;
00196 DIEFFECT diEffect;
00197
00198 cf.lOffset = static_cast<ConditionalEffect*>(effect->getForceEffect())->deadband;
00199 cf.lPositiveCoefficient = static_cast<ConditionalEffect*>(effect->getForceEffect())->rightCoeff;
00200 cf.lNegativeCoefficient = static_cast<ConditionalEffect*>(effect->getForceEffect())->leftCoeff;
00201 cf.dwPositiveSaturation = static_cast<ConditionalEffect*>(effect->getForceEffect())->rightSaturation;
00202 cf.dwNegativeSaturation = static_cast<ConditionalEffect*>(effect->getForceEffect())->leftSaturation;
00203 cf.lDeadBand = static_cast<ConditionalEffect*>(effect->getForceEffect())->deadband;
00204
00205 _setCommonProperties(&diEffect, rgdwAxes, rglDirection, sizeof(DICONDITION), &cf, effect);
00206
00207 switch( effect->type )
00208 {
00209 case OIS::Effect::Friction: _upload(GUID_Friction, &diEffect, effect); break;
00210 case OIS::Effect::Damper: _upload(GUID_Damper, &diEffect, effect); break;
00211 case OIS::Effect::Inertia: _upload(GUID_Inertia, &diEffect, effect); break;
00212 case OIS::Effect::Spring: _upload(GUID_Spring, &diEffect, effect); break;
00213 default: break;
00214 }
00215 }
00216
00217
00218 void Win32ForceFeedback::_updateCustomEffect( const Effect* )
00219 {
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 }
00231
00232
00233 void Win32ForceFeedback::_setCommonProperties(
00234 DIEFFECT* diEffect, DWORD* rgdwAxes,
00235 LONG* rglDirection, DWORD struct_size,
00236 LPVOID struct_type, const Effect* effect )
00237 {
00238 ZeroMemory(diEffect, sizeof(DIEFFECT));
00239
00240 diEffect->dwSize = sizeof(DIEFFECT);
00241 diEffect->dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
00242 diEffect->dwDuration = effect->replay_length;
00243 diEffect->dwSamplePeriod = 0;
00244 diEffect->dwGain = DI_FFNOMINALMAX;
00245 diEffect->dwTriggerButton = DIEB_NOTRIGGER;
00246 diEffect->dwTriggerRepeatInterval = 0;
00247 diEffect->cAxes = effect->getNumAxes();
00248 diEffect->rgdwAxes = rgdwAxes;
00249 diEffect->rglDirection = rglDirection;
00250 diEffect->lpEnvelope = 0;
00251 diEffect->cbTypeSpecificParams = struct_size;
00252 diEffect->lpvTypeSpecificParams = struct_type;
00253 diEffect->dwStartDelay = effect->replay_delay;
00254 }
00255
00256
00257 void Win32ForceFeedback::_upload( GUID guid, DIEFFECT* diEffect, const Effect* effect)
00258 {
00259 LPDIRECTINPUTEFFECT dxEffect = 0;
00260
00261
00262 EffectList::iterator i = mEffectList.find(effect->_handle);
00263
00264 if( i != mEffectList.end() )
00265 dxEffect = i->second;
00266 else
00267 effect->_handle = mHandles++;
00268
00269 if( dxEffect == 0 )
00270 {
00271
00272 HRESULT hr = mJoyStick->CreateEffect(guid, diEffect, &dxEffect, NULL);
00273 if(SUCCEEDED(hr))
00274 {
00275 mEffectList[effect->_handle] = dxEffect;
00276 dxEffect->Start(INFINITE,0);
00277 }
00278 else if( hr == DIERR_DEVICEFULL )
00279 OIS_EXCEPT(E_DeviceFull, "Remove an effect before adding more!");
00280 else
00281 OIS_EXCEPT(E_General, "Unknown error creating effect->..");
00282 }
00283 else
00284 {
00285
00286 HRESULT hr = dxEffect->SetParameters( diEffect, DIEP_DIRECTION |
00287 DIEP_DURATION | DIEP_ENVELOPE | DIEP_STARTDELAY | DIEP_TRIGGERBUTTON |
00288 DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS | DIEP_START );
00289
00290 if(FAILED(hr)) OIS_EXCEPT(E_InvalidParam, "Error updating device!");
00291 }
00292 }
00293
00294
00295 void Win32ForceFeedback::_addEffectSupport( LPCDIEFFECTINFO pdei )
00296 {
00297
00298
00299
00300 if( pdei->guid == GUID_ConstantForce )
00301 _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Constant );
00302 else if( pdei->guid == GUID_Triangle )
00303 _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Triangle );
00304 else if( pdei->guid == GUID_Spring )
00305 _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Spring );
00306 else if( pdei->guid == GUID_Friction )
00307 _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Friction );
00308 else if( pdei->guid == GUID_Square )
00309 _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Square );
00310 else if( pdei->guid == GUID_Sine )
00311 _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Sine );
00312 else if( pdei->guid == GUID_SawtoothUp )
00313 _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::SawToothUp );
00314 else if( pdei->guid == GUID_SawtoothDown )
00315 _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::SawToothDown );
00316 else if( pdei->guid == GUID_Damper )
00317 _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Damper );
00318 else if( pdei->guid == GUID_Inertia )
00319 _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Inertia );
00320 else if( pdei->guid == GUID_CustomForce )
00321 _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Custom );
00322 else if( pdei->guid == GUID_RampForce )
00323 _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Ramp );
00324 #if defined (_DEBUG)
00325
00326
00327
00328
00329
00330
00331
00332
00333 #endif
00334 }