E:/Download/ois-1.0RC1/src/win32/Win32ForceFeedback.cpp

Go to the documentation of this file.
00001 /*
00002 The zlib/libpng License
00003 
00004 Copyright (c) 2006 Phillip Castaneda (pjcast -- www.wreckedgames.com)
00005 
00006 This software is provided 'as-is', without any express or implied warranty. In no event will
00007 the authors be held liable for any damages arising from the use of this software.
00008 
00009 Permission is granted to anyone to use this software for any purpose, including commercial
00010 applications, and to alter it and redistribute it freely, subject to the following
00011 restrictions:
00012 
00013     1. The origin of this software must not be misrepresented; you must not claim that
00014                 you wrote the original software. If you use this software in a product,
00015                 an acknowledgment in the product documentation would be appreciated but is
00016                 not required.
00017 
00018     2. Altered source versions must be plainly marked as such, and must not be
00019                 misrepresented as being the original software.
00020 
00021     3. This notice may not be removed or altered from any source distribution.
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         //Get the effect - if it exists
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                 //case OIS::Effect::CustomForce: _updateCustomEffect(effect); break;
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         //Modifying is essentially the same as an upload, so, just reuse that function
00071         upload(eff);
00072 }
00073 
00074 //--------------------------------------------------------------//
00075 void Win32ForceFeedback::remove( const Effect* eff )
00076 {
00077         //Get the effect - if it exists
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                         //We care about the return value - as the effect might not
00086                         //have been unlaoded
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         //Between 0 - 10,000
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         //DI Property DIPROPAUTOCENTER_OFF = 0, 1 is on
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         //hr =
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         //Currently only support 1 axis
00140         //if( effect->getNumAxes() == 1 )
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         //Currently only support 1 axis
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         //Currently only support 1 axis
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* /*effect*/ )
00219 {
00220         //DWORD           rgdwAxes[2]     = { DIJOFS_X, DIJOFS_Y };
00221         //LONG            rglDirection[2] = { 0, 0 };
00222         //DICUSTOMFORCE cf;
00223         //DIEFFECT        diEffect;
00224         //cf.cChannels = 0;
00225         //cf.dwSamplePeriod = 0;
00226         //cf.cSamples = 0;
00227         //cf.rglForceData = 0;
00228         //_setCommonProperties(&diEffect, rgdwAxes, rglDirection, sizeof(DICUSTOMFORCE), &cf, effect);
00229         //_upload(GUID_CustomForce, &diEffect, effect);
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         //Get the effect - if it exists
00262         EffectList::iterator i = mEffectList.find(effect->_handle);
00263         //It has been created already
00264         if( i != mEffectList.end() )
00265                 dxEffect = i->second;
00266         else //This effect has not yet been created - generate a handle
00267                 effect->_handle = mHandles++;
00268 
00269         if( dxEffect == 0 )
00270         {
00271                 //This effect has not yet been created, so create it
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                 //ToDo -- Update the Effect
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         //Determine what the effect is and how it corresponds to our OIS's Enums
00298         //We could save the GUIDs too, however, we will just use the predefined
00299         //ones later
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         //Only care about this for Debugging Purposes
00326         //else
00327         //{
00328         //      std::ostringstream ss;
00329         //      ss << "Win32ForceFeedback, DirectInput8 Effect not found. Reported as: "
00330         //         << pdei->tszName;
00331         //      OIS_EXCEPT( E_General, ss.str().c_str());
00332         //}
00333 #endif
00334 }

Generated on Sat Dec 1 20:13:52 2007 for OIS by  doxygen 1.5.4