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 //-----------------------------------------------------------------------------------// 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 //-----------------------------------------------------------------------------------// 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 //-----------------------------------------------------------------------------------// 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 //-----------------------------------------------------------------------------------// 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 //-----------------------------------------------------------------------------------// 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 //-----------------------------------------------------------------------------------// 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 //-----------------------------------------------------------------------------------// 277 void WiiMote::setBuffered(bool buffered) 278 { 279 mBuffered = buffered; 280 } 281 282 //-----------------------------------------------------------------------------------// 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[b] = 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[b] = false; 358 if( mBuffered && mListener ) 359 if( !mListener->buttonReleased( JoyStickEvent( this, mState ), b ) ) return; 360 } 361 } 362 } 363 } 364 365 //-----------------------------------------------------------------------------------// 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