1 #include "OISConfig.h"
2 #ifdef OIS_WIN32_WIIMOTE_SUPPORT
3 /*
4 The zlib/libpng License
5
6 Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
7
8 This software is provided 'as-is', without any express or implied warranty. In no event will
9 the authors be held liable for any damages arising from the use of this software.
10
11 Permission is granted to anyone to use this software for any purpose, including commercial
12 applications, and to alter it and redistribute it freely, subject to the following
13 restrictions:
14
15 1. The origin of this software must not be misrepresented; you must not claim that
16 you wrote the original software. If you use this software in a product,
17 an acknowledgment in the product documentation would be appreciated but is
18 not required.
19
20 2. Altered source versions must be plainly marked as such, and must not be
21 misrepresented as being the original software.
22
23 3. This notice may not be removed or altered from any source distribution.
24 */
25 #include "OISWiiMote.h"
26 #include "OISWiiMoteFactoryCreator.h"
27 #include "OISException.h"
28 #include "OISWiiMoteForceFeedback.h"
29 #define _USE_MATH_DEFINES
30 #include <math.h>
31 #include <limits.h>
32
33 using namespace OIS;
34
35 //-----------------------------------------------------------------------------------//
WiiMote(InputManager * creator,int id,bool buffered,WiiMoteFactoryCreator * local_creator)36 WiiMote::WiiMote(InputManager* creator, int id, bool buffered, WiiMoteFactoryCreator* local_creator) :
37 JoyStick("cWiiMote", buffered, id, creator),
38 mWiiCreator(local_creator),
39 mtInitialized(false),
40 mRingBuffer(OIS_WII_EVENT_BUFFER),
41 mtLastButtonStates(0),
42 mtLastPOVState(0),
43 mtLastX(0.0f),
44 mtLastY(1.0f),
45 mtLastZ(0.0f),
46 mtLastNunChuckX(0.0f),
47 mtLastNunChuckY(1.0f),
48 mtLastNunChuckZ(0.0f),
49 mLastNunChuckXAxis(0),
50 mLastNunChuckYAxis(0),
51 _mWiiMoteMotionDelay(5),
52 mRumble(0)
53 {
54 mRumble = new WiiMoteForceFeedback(mWiiMote);
55 }
56
57 //-----------------------------------------------------------------------------------//
~WiiMote()58 WiiMote::~WiiMote()
59 {
60 delete mRumble;
61
62 if( mWiiMote.IsConnected() )
63 {
64 mWiiMote.StopDataStream();
65 mWiiMote.Disconnect();
66 }
67 mWiiCreator->_returnWiiMote(mDevID);
68 }
69
70 //-----------------------------------------------------------------------------------//
_initialize()71 void WiiMote::_initialize()
72 {
73 if( mWiiMote.ConnectToDevice(mDevID) == false )
74 OIS_EXCEPT(E_InputDisconnected, "Error connecting to WiiMote!");
75
76 if( mWiiMote.StartDataStream() == false )
77 OIS_EXCEPT(E_InputDisconnected, "Error starting WiiMote data stream!");
78
79 //Fill in joystick information
80 mState.mVectors.clear();
81 mState.mButtons.clear();
82 mState.mAxes.clear();
83
84 if( mWiiMote.IsNunChuckAttached() )
85 { //Setup for WiiMote + nunChuck
86 mState.mVectors.resize(2);
87 mState.mButtons.resize(9);
88 mState.mAxes.resize(2);
89 mState.mAxes[0].absOnly = true;
90 mState.mAxes[1].absOnly = true;
91 }
92 else
93 { //Setup for WiiMote
94 mState.mVectors.resize(1);
95 mState.mButtons.resize(7);
96 }
97
98 mPOVs = 1;
99 mState.clear();
100 mtInitialized = true;
101 }
102
103 //-----------------------------------------------------------------------------------//
_threadUpdate()104 void WiiMote::_threadUpdate()
105 {
106 //Leave early if nothing is setup yet
107 if( mtInitialized == false )
108 return;
109
110 //Oops, no room left in ring buffer.. have to wait for client app to call Capture()
111 if( mRingBuffer.GetWriteAvailable() == 0 )
112 return;
113
114 WiiMoteEvent newEvent;
115 newEvent.clear();
116
117 //Update read
118 mWiiMote.HeartBeat();
119
120 //Get & check current button states
121 const cWiiMote::tButtonStatus &bState = mWiiMote.GetLastButtonStatus();
122 _doButtonCheck(bState.m1, 0, newEvent.pushedButtons, newEvent.releasedButtons); //1
123 _doButtonCheck(bState.m2, 1, newEvent.pushedButtons, newEvent.releasedButtons); //2
124 _doButtonCheck(bState.mA, 2, newEvent.pushedButtons, newEvent.releasedButtons); //A
125 _doButtonCheck(bState.mB, 3, newEvent.pushedButtons, newEvent.releasedButtons); //B
126 _doButtonCheck(bState.mPlus, 4, newEvent.pushedButtons, newEvent.releasedButtons);//+
127 _doButtonCheck(bState.mMinus, 5, newEvent.pushedButtons, newEvent.releasedButtons);//-
128 _doButtonCheck(bState.mHome, 6, newEvent.pushedButtons, newEvent.releasedButtons);//Home
129
130 //Check POV
131 newEvent.povChanged = _doPOVCheck(bState, newEvent.povDirection);
132
133 //Do motion check on main orientation - accounting for sensitivity factor
134 mWiiMote.GetCalibratedAcceleration(newEvent.x, newEvent.y, newEvent.z);
135 //Normalize new vector (old vector is already normalized)
136 float len = sqrt((newEvent.x*newEvent.x) + (newEvent.y*newEvent.y) + (newEvent.z*newEvent.z));
137 newEvent.x /= len;
138 newEvent.y /= len;
139 newEvent.z /= len;
140
141 //Get new angle
142 float angle = acos((newEvent.x * mtLastX) + (newEvent.y * mtLastY) + (newEvent.z * mtLastZ));
143 if( angle > (mVector3Sensitivity * (M_PI / 180.0)) )
144 { //Store for next check
145 mtLastX = newEvent.x;
146 mtLastY = newEvent.y;
147 mtLastZ = newEvent.z;
148
149 if( _mWiiMoteMotionDelay <= 0 )
150 newEvent.movement = true; //Set flag as moved
151 else
152 --_mWiiMoteMotionDelay;
153 }
154
155 //Act on NunChuck Data
156 if( mWiiMote.IsNunChuckAttached() )
157 {
158 const cWiiMote::tChuckReport &bState = mWiiMote.GetLastChuckReport();
159 _doButtonCheck(bState.mButtonC, 7, newEvent.pushedButtons, newEvent.releasedButtons); //C
160 _doButtonCheck(bState.mButtonZ, 8, newEvent.pushedButtons, newEvent.releasedButtons); //Z
161
162 mWiiMote.GetCalibratedChuckAcceleration(newEvent.nunChuckx, newEvent.nunChucky, newEvent.nunChuckz);
163 //Normalize new vector (old vector is already normalized)
164 float len = sqrt((newEvent.nunChuckx*newEvent.nunChuckx) +
165 (newEvent.nunChucky*newEvent.nunChucky) +
166 (newEvent.nunChuckz*newEvent.nunChuckz));
167
168 newEvent.nunChuckx /= len;
169 newEvent.nunChucky /= len;
170 newEvent.nunChuckz /= len;
171
172 float angle = acos((newEvent.nunChuckx * mtLastNunChuckX) +
173 (newEvent.nunChucky * mtLastNunChuckY) +
174 (newEvent.nunChuckz * mtLastNunChuckZ));
175
176 if( angle > (mVector3Sensitivity * (M_PI / 180.0)) )
177 { //Store for next check
178 mtLastNunChuckX = newEvent.nunChuckx;
179 mtLastNunChuckY = newEvent.nunChucky;
180 mtLastNunChuckZ = newEvent.nunChuckz;
181
182 if( _mWiiMoteMotionDelay <= 0 )
183 newEvent.movementChuck = true;
184 }
185
186 //Ok, Now check both NunChuck Joystick axes for movement
187 float tempX = 0.0f, tempY = 0.0f;
188 mWiiMote.GetCalibratedChuckStick(tempX, tempY);
189
190 //Convert to int and clip
191 newEvent.nunChuckXAxis = (int)(tempX * JoyStick::MAX_AXIS);
192 if( newEvent.nunChuckXAxis > JoyStick::MAX_AXIS )
193 newEvent.nunChuckXAxis = JoyStick::MAX_AXIS;
194 else if( newEvent.nunChuckXAxis < JoyStick::MIN_AXIS )
195 newEvent.nunChuckXAxis = JoyStick::MIN_AXIS;
196
197 newEvent.nunChuckYAxis = (int)(tempY * JoyStick::MAX_AXIS);
198 if( newEvent.nunChuckYAxis > JoyStick::MAX_AXIS )
199 newEvent.nunChuckYAxis = JoyStick::MAX_AXIS;
200 else if( newEvent.nunChuckYAxis < JoyStick::MIN_AXIS )
201 newEvent.nunChuckYAxis = JoyStick::MIN_AXIS;
202
203 //Apply a little dead-zone dampner
204 int xDiff = newEvent.nunChuckXAxis - mLastNunChuckXAxis;
205 if( xDiff > 1500 || xDiff < -1500 )
206 {
207 mLastNunChuckXAxis = newEvent.nunChuckXAxis;
208 newEvent.nunChuckXAxisMoved = true;
209 }
210
211 int yDiff = newEvent.nunChuckYAxis - mLastNunChuckYAxis;
212 if( yDiff > 1500 || yDiff < -1500 )
213 {
214 mLastNunChuckYAxis = newEvent.nunChuckYAxis;
215 newEvent.nunChuckYAxisMoved = true;
216 }
217 }
218
219 //Ok, put entry in ringbuffer if something changed
220 if(newEvent.pushedButtons || newEvent.releasedButtons || newEvent.povChanged || newEvent.movement ||
221 newEvent.movementChuck || newEvent.nunChuckXAxisMoved || newEvent.nunChuckYAxisMoved)
222 {
223 mRingBuffer.Write(&newEvent, 1);
224 }
225
226 //mWiiMote.PrintStatus();
227 }
228
229 //-----------------------------------------------------------------------------------//
_doButtonCheck(bool new_state,int ois_button,unsigned int & pushed,unsigned int & released)230 void WiiMote::_doButtonCheck(bool new_state, int ois_button, unsigned int &pushed, unsigned int &released)
231 {
232 const bool old_state = ((mtLastButtonStates & ( 1L << ois_button )) == 0) ? false : true;
233
234 //Check to see if new state and old state are the same, and hence, need no change
235 if( new_state == old_state )
236 return;
237
238 //Ok, so it changed... but how?
239 if( new_state )
240 { //Ok, new state is pushed, old state was not pushed.. so send button press
241 mtLastButtonStates |= 1 << ois_button; //turn the bit flag on
242 pushed |= 1 << ois_button;
243 }
244 else
245 { //Ok, so new state is not pushed, and old state was pushed.. So, send release
246 mtLastButtonStates &= ~(1 << ois_button); //turn the bit flag off
247 released |= 1 << ois_button;
248 }
249 }
250
251 //-----------------------------------------------------------------------------------//
_doPOVCheck(const cWiiMote::tButtonStatus & bState,unsigned int & newPosition)252 bool WiiMote::_doPOVCheck(const cWiiMote::tButtonStatus &bState, unsigned int &newPosition)
253 {
254 newPosition = Pov::Centered;
255
256 if( bState.mUp )
257 newPosition |= Pov::North;
258 else if( bState.mDown )
259 newPosition |= Pov::South;
260
261 if( bState.mLeft )
262 newPosition |= Pov::West;
263 else if( bState.mRight )
264 newPosition |= Pov::East;
265
266 //Was there a change?
267 if( mtLastPOVState != newPosition )
268 {
269 mtLastPOVState = newPosition;
270 return true;
271 }
272
273 return false;
274 }
275
276 //-----------------------------------------------------------------------------------//
setBuffered(bool buffered)277 void WiiMote::setBuffered(bool buffered)
278 {
279 mBuffered = buffered;
280 }
281
282 //-----------------------------------------------------------------------------------//
capture()283 void WiiMote::capture()
284 {
285 //Anything to read?
286 int entries = mRingBuffer.GetReadAvailable();
287 if( entries <= 0 )
288 return;
289
290 WiiMoteEvent events[OIS_WII_EVENT_BUFFER];
291 if( entries > OIS_WII_EVENT_BUFFER )
292 entries = OIS_WII_EVENT_BUFFER;
293
294 mRingBuffer.Read(events, entries);
295
296 //Loop through each event
297 for( int i = 0; i < entries; ++i )
298 {
299 //Any movement changes in the main accellerometers?
300 if( events[i].movement )
301 {
302 mState.mVectors[0].x = events[i].x;
303 mState.mVectors[0].y = events[i].y;
304 mState.mVectors[0].z = events[i].z;
305 if( mBuffered && mListener )
306 if( !mListener->vector3Moved( JoyStickEvent( this, mState ), 0 ) ) return;
307 }
308
309 //Check NunChuck movements
310 if( events[i].movementChuck )
311 {
312 mState.mVectors[1].x = events[i].nunChuckx;
313 mState.mVectors[1].y = events[i].nunChucky;
314 mState.mVectors[1].z = events[i].nunChuckz;
315 if( mBuffered && mListener )
316 if( !mListener->vector3Moved( JoyStickEvent( this, mState ), 1 ) ) return;
317 }
318
319 if( events[i].nunChuckXAxisMoved )
320 {
321 mState.mAxes[0].abs = events[i].nunChuckXAxis;
322
323 if( mBuffered && mListener )
324 if( !mListener->axisMoved( JoyStickEvent( this, mState ), 0 ) ) return;
325 }
326
327 if( events[i].nunChuckYAxisMoved )
328 {
329 mState.mAxes[1].abs = events[i].nunChuckYAxis;
330
331 if( mBuffered && mListener )
332 if( !mListener->axisMoved( JoyStickEvent( this, mState ), 1 ) ) return;
333 }
334
335 //Has the hat swtich changed?
336 if( events[i].povChanged )
337 {
338 mState.mPOV[0].direction = events[i].povDirection;
339 if( mBuffered && mListener )
340 if( !mListener->povMoved( JoyStickEvent( this, mState ), 0 ) ) return;
341 }
342
343 //Check for any pushed/released events for each button bit
344 int buttons = (int)mState.mButtons.size();
345 for( int b = 0; b < buttons; ++b )
346 {
347 unsigned bit_flag = 1 << b;
348 if( (events[i].pushedButtons & bit_flag) != 0 )
349 { //send event
350 mState.mButtons[i] = true;
351 if( mBuffered && mListener )
352 if( !mListener->buttonPressed( JoyStickEvent( this, mState ), b ) ) return;
353 }
354
355 if( (events[i].releasedButtons & bit_flag) != 0 )
356 { //send event
357 mState.mButtons[i] = false;
358 if( mBuffered && mListener )
359 if( !mListener->buttonReleased( JoyStickEvent( this, mState ), b ) ) return;
360 }
361 }
362 }
363 }
364
365 //-----------------------------------------------------------------------------------//
queryInterface(Interface::IType type)366 Interface* WiiMote::queryInterface(Interface::IType type)
367 {
368 if( type == Interface::ForceFeedback && mtInitialized )
369 return mRumble;
370
371 return 0;
372 }
373 #endif
374