Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/ois/win32/Win32ForceFeedback.cpp @ 1486

Last change on this file since 1486 was 1219, checked in by rgrieder, 17 years ago

merged input branch back to trunk. Not yet tested on tardis

File size: 12.7 KB
Line 
1/*
2The zlib/libpng License
3
4Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
5
6This software is provided 'as-is', without any express or implied warranty. In no event will
7the authors be held liable for any damages arising from the use of this software.
8
9Permission is granted to anyone to use this software for any purpose, including commercial
10applications, and to alter it and redistribute it freely, subject to the following
11restrictions:
12
13    1. The origin of this software must not be misrepresented; you must not claim that
14                you wrote the original software. If you use this software in a product,
15                an acknowledgment in the product documentation would be appreciated but is
16                not required.
17
18    2. Altered source versions must be plainly marked as such, and must not be
19                misrepresented as being the original software.
20
21    3. This notice may not be removed or altered from any source distribution.
22*/
23#include "Win32/Win32ForceFeedback.h"
24#include "OISException.h"
25#include <Math.h>
26
27#if defined (_DEBUG)
28  #include <sstream>
29#endif
30
31using namespace OIS;
32
33//--------------------------------------------------------------//
34Win32ForceFeedback::Win32ForceFeedback(IDirectInputDevice8* joy) :
35        mHandles(0), mJoyStick(joy)
36{
37}
38
39//--------------------------------------------------------------//
40Win32ForceFeedback::~Win32ForceFeedback()
41{
42        //Get the effect - if it exists
43        for(EffectList::iterator i = mEffectList.begin(); i != mEffectList.end(); ++i )
44        {
45                LPDIRECTINPUTEFFECT dxEffect = i->second;
46                if( dxEffect )
47                        dxEffect->Unload();
48        }
49
50        mEffectList.clear();
51}
52
53//--------------------------------------------------------------//
54void Win32ForceFeedback::upload( const Effect* effect )
55{
56        switch( effect->force )
57        {
58                case OIS::Effect::ConstantForce: _updateConstantEffect(effect); break;
59                case OIS::Effect::RampForce: _updateRampEffect(effect); break;
60                case OIS::Effect::PeriodicForce: _updatePeriodicEffect(effect); break;
61                case OIS::Effect::ConditionalForce:     _updateConditionalEffect(effect); break;
62                //case OIS::Effect::CustomForce: _updateCustomEffect(effect); break;
63                default: OIS_EXCEPT(E_NotImplemented, "Requested Force not Implemented yet, sorry!"); break;
64        }
65}
66
67//--------------------------------------------------------------//
68void Win32ForceFeedback::modify( const Effect* eff )
69{
70        //Modifying is essentially the same as an upload, so, just reuse that function
71        upload(eff);
72}
73
74//--------------------------------------------------------------//
75void Win32ForceFeedback::remove( const Effect* eff )
76{
77        //Get the effect - if it exists
78        EffectList::iterator i = mEffectList.find(eff->_handle);
79        if( i != mEffectList.end() )
80        {
81                LPDIRECTINPUTEFFECT dxEffect = i->second;
82                if( dxEffect )
83                {
84                        dxEffect->Stop();
85                        //We care about the return value - as the effect might not
86                        //have been unlaoded
87                        if( SUCCEEDED(dxEffect->Unload()) )
88                                mEffectList.erase(i);
89                }
90                else
91                        mEffectList.erase(i);
92        }
93}
94
95//--------------------------------------------------------------//
96void Win32ForceFeedback::setMasterGain( float level )
97{
98        //Between 0 - 10,000
99        int gain_level = (int)(10000.0f * level);
100
101        if( gain_level > 10000 )
102                gain_level = 10000;
103        else if( gain_level < 0 )
104                gain_level = 0;
105
106        DIPROPDWORD DIPropGain;
107        DIPropGain.diph.dwSize       = sizeof(DIPropGain);
108        DIPropGain.diph.dwHeaderSize = sizeof(DIPROPHEADER);
109        DIPropGain.diph.dwObj        = 0;
110        DIPropGain.diph.dwHow        = DIPH_DEVICE;
111        DIPropGain.dwData            = gain_level;
112
113        mJoyStick->SetProperty(DIPROP_FFGAIN, &DIPropGain.diph);
114}
115
116//--------------------------------------------------------------//
117void Win32ForceFeedback::setAutoCenterMode( bool auto_on )
118{
119        //DI Property DIPROPAUTOCENTER_OFF = 0, 1 is on
120        DIPROPDWORD DIPropAutoCenter;
121        DIPropAutoCenter.diph.dwSize       = sizeof(DIPropAutoCenter);
122        DIPropAutoCenter.diph.dwHeaderSize = sizeof(DIPROPHEADER);
123        DIPropAutoCenter.diph.dwObj        = 0;
124        DIPropAutoCenter.diph.dwHow        = DIPH_DEVICE;
125        DIPropAutoCenter.dwData            = auto_on;
126
127        //hr =
128        mJoyStick->SetProperty(DIPROP_AUTOCENTER, &DIPropAutoCenter.diph);
129}
130
131//--------------------------------------------------------------//
132void Win32ForceFeedback::_updateConstantEffect( const Effect* effect )
133{
134        DWORD           rgdwAxes[2]     = { DIJOFS_X, DIJOFS_Y };
135        LONG            rglDirection[2] = { 0, 0 };
136        DICONSTANTFORCE cf;
137        DIEFFECT        diEffect;
138
139        //Currently only support 1 axis
140        //if( effect->getNumAxes() == 1 )
141        cf.lMagnitude = static_cast<ConstantEffect*>(effect->getForceEffect())->level;
142
143        _setCommonProperties(&diEffect, rgdwAxes, rglDirection, sizeof(DICONSTANTFORCE), &cf, effect);
144        _upload(GUID_ConstantForce, &diEffect, effect);
145}
146
147//--------------------------------------------------------------//
148void Win32ForceFeedback::_updateRampEffect( const Effect* effect )
149{
150        DWORD           rgdwAxes[2]     = { DIJOFS_X, DIJOFS_Y };
151        LONG            rglDirection[2] = { 0, 0 };
152        DIRAMPFORCE     rf;
153        DIEFFECT        diEffect;
154
155        //Currently only support 1 axis
156        rf.lStart = static_cast<RampEffect*>(effect->getForceEffect())->startLevel;
157        rf.lEnd = static_cast<RampEffect*>(effect->getForceEffect())->endLevel;
158
159        _setCommonProperties(&diEffect, rgdwAxes, rglDirection, sizeof(DIRAMPFORCE), &rf, effect);
160        _upload(GUID_RampForce, &diEffect, effect);
161}
162
163//--------------------------------------------------------------//
164void Win32ForceFeedback::_updatePeriodicEffect( const Effect* effect )
165{
166        DWORD           rgdwAxes[2]     = { DIJOFS_X, DIJOFS_Y };
167        LONG            rglDirection[2] = { 0, 0 };
168        DIPERIODIC      pf;
169        DIEFFECT        diEffect;
170
171        //Currently only support 1 axis
172        pf.dwMagnitude = static_cast<PeriodicEffect*>(effect->getForceEffect())->magnitude;
173        pf.lOffset = static_cast<PeriodicEffect*>(effect->getForceEffect())->offset;
174        pf.dwPhase = static_cast<PeriodicEffect*>(effect->getForceEffect())->phase;
175        pf.dwPeriod = static_cast<PeriodicEffect*>(effect->getForceEffect())->period;
176
177        _setCommonProperties(&diEffect, rgdwAxes, rglDirection, sizeof(DIPERIODIC), &pf, effect);
178
179        switch( effect->type )
180        {
181        case OIS::Effect::Square: _upload(GUID_Square, &diEffect, effect); break;
182        case OIS::Effect::Triangle: _upload(GUID_Triangle, &diEffect, effect); break;
183        case OIS::Effect::Sine: _upload(GUID_Sine, &diEffect, effect); break;
184        case OIS::Effect::SawToothUp: _upload(GUID_SawtoothUp, &diEffect, effect); break;
185        case OIS::Effect::SawToothDown: _upload(GUID_SawtoothDown, &diEffect, effect); break;
186        default: break;
187        }
188}
189
190//--------------------------------------------------------------//
191void Win32ForceFeedback::_updateConditionalEffect( const Effect* effect )
192{
193        DWORD           rgdwAxes[2]     = { DIJOFS_X, DIJOFS_Y };
194        LONG            rglDirection[2] = { 0, 0 };
195        DICONDITION     cf;
196        DIEFFECT        diEffect;
197
198        cf.lOffset = static_cast<ConditionalEffect*>(effect->getForceEffect())->deadband;
199        cf.lPositiveCoefficient = static_cast<ConditionalEffect*>(effect->getForceEffect())->rightCoeff;
200        cf.lNegativeCoefficient = static_cast<ConditionalEffect*>(effect->getForceEffect())->leftCoeff;
201        cf.dwPositiveSaturation = static_cast<ConditionalEffect*>(effect->getForceEffect())->rightSaturation;
202        cf.dwNegativeSaturation = static_cast<ConditionalEffect*>(effect->getForceEffect())->leftSaturation;
203        cf.lDeadBand = static_cast<ConditionalEffect*>(effect->getForceEffect())->deadband;
204
205        _setCommonProperties(&diEffect, rgdwAxes, rglDirection, sizeof(DICONDITION), &cf, effect);
206
207        switch( effect->type )
208        {
209        case OIS::Effect::Friction:     _upload(GUID_Friction, &diEffect, effect); break;
210        case OIS::Effect::Damper: _upload(GUID_Damper, &diEffect, effect); break;
211        case OIS::Effect::Inertia: _upload(GUID_Inertia, &diEffect, effect); break;
212        case OIS::Effect::Spring: _upload(GUID_Spring, &diEffect, effect); break;
213        default: break;
214        }
215}
216
217//--------------------------------------------------------------//
218void Win32ForceFeedback::_updateCustomEffect( const Effect* /*effect*/ )
219{
220        //DWORD           rgdwAxes[2]     = { DIJOFS_X, DIJOFS_Y };
221        //LONG            rglDirection[2] = { 0, 0 };
222        //DICUSTOMFORCE cf;
223        //DIEFFECT        diEffect;
224        //cf.cChannels = 0;
225        //cf.dwSamplePeriod = 0;
226        //cf.cSamples = 0;
227        //cf.rglForceData = 0;
228        //_setCommonProperties(&diEffect, rgdwAxes, rglDirection, sizeof(DICUSTOMFORCE), &cf, effect);
229        //_upload(GUID_CustomForce, &diEffect, effect);
230}
231
232//--------------------------------------------------------------//
233void Win32ForceFeedback::_setCommonProperties(
234                DIEFFECT* diEffect, DWORD* rgdwAxes,
235                LONG* rglDirection, DWORD struct_size,
236                LPVOID struct_type, const Effect* effect )
237{
238        ZeroMemory(diEffect, sizeof(DIEFFECT));
239
240        diEffect->dwSize                  = sizeof(DIEFFECT);
241        diEffect->dwFlags                 = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
242        diEffect->dwDuration              = effect->replay_length;
243        diEffect->dwSamplePeriod          = 0;
244        diEffect->dwGain                  = DI_FFNOMINALMAX;
245        diEffect->dwTriggerButton         = DIEB_NOTRIGGER;
246        diEffect->dwTriggerRepeatInterval = 0;
247        diEffect->cAxes                   = effect->getNumAxes();
248        diEffect->rgdwAxes                = rgdwAxes;
249        diEffect->rglDirection            = rglDirection;
250        diEffect->lpEnvelope              = 0;
251        diEffect->cbTypeSpecificParams    = struct_size;
252        diEffect->lpvTypeSpecificParams   = struct_type;
253        diEffect->dwStartDelay            = effect->replay_delay;
254}
255
256//--------------------------------------------------------------//
257void Win32ForceFeedback::_upload( GUID guid, DIEFFECT* diEffect, const Effect* effect)
258{
259        LPDIRECTINPUTEFFECT dxEffect = 0;
260
261        //Get the effect - if it exists
262        EffectList::iterator i = mEffectList.find(effect->_handle);
263        //It has been created already
264        if( i != mEffectList.end() )
265                dxEffect = i->second;
266        else //This effect has not yet been created - generate a handle
267                effect->_handle = mHandles++;
268
269        if( dxEffect == 0 )
270        {
271                //This effect has not yet been created, so create it
272                HRESULT hr = mJoyStick->CreateEffect(guid, diEffect, &dxEffect, NULL);
273                if(SUCCEEDED(hr))
274                {
275                        mEffectList[effect->_handle] = dxEffect;
276                        dxEffect->Start(INFINITE,0);
277                }
278                else if( hr == DIERR_DEVICEFULL )
279                        OIS_EXCEPT(E_DeviceFull, "Remove an effect before adding more!");
280                else
281                        OIS_EXCEPT(E_General, "Unknown error creating effect->..");
282        }
283        else
284        {
285                //ToDo -- Update the Effect
286                HRESULT hr = dxEffect->SetParameters( diEffect, DIEP_DIRECTION |
287                        DIEP_DURATION | DIEP_ENVELOPE | DIEP_STARTDELAY | DIEP_TRIGGERBUTTON |
288                        DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS | DIEP_START );
289
290                if(FAILED(hr)) OIS_EXCEPT(E_InvalidParam, "Error updating device!");
291        }
292}
293
294//--------------------------------------------------------------//
295void Win32ForceFeedback::_addEffectSupport( LPCDIEFFECTINFO pdei )
296{
297        //Determine what the effect is and how it corresponds to our OIS's Enums
298        //We could save the GUIDs too, however, we will just use the predefined
299        //ones later
300        if( pdei->guid == GUID_ConstantForce )
301                _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Constant );
302        else if( pdei->guid == GUID_Triangle )
303                _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Triangle );
304        else if( pdei->guid == GUID_Spring )
305                _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Spring );
306        else if( pdei->guid == GUID_Friction )
307                _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Friction );
308        else if( pdei->guid == GUID_Square )
309                _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Square );
310        else if( pdei->guid == GUID_Sine )
311                _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Sine );
312        else if( pdei->guid == GUID_SawtoothUp )
313                _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::SawToothUp );
314        else if( pdei->guid == GUID_SawtoothDown )
315                _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::SawToothDown );
316        else if( pdei->guid == GUID_Damper )
317                _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Damper );
318        else if( pdei->guid == GUID_Inertia )
319                _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Inertia );
320        else if( pdei->guid == GUID_CustomForce )
321                _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Custom );
322        else if( pdei->guid == GUID_RampForce )
323                _addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Ramp );
324#if defined (_DEBUG)
325        //Only care about this for Debugging Purposes
326        //else
327        //{
328        //      std::ostringstream ss;
329        //      ss << "Win32ForceFeedback, DirectInput8 Effect not found. Reported as: "
330        //         << pdei->tszName;
331        //      OIS_EXCEPT( E_General, ss.str().c_str());
332        //}
333#endif
334}
Note: See TracBrowser for help on using the repository browser.