Home | History | Annotate | Download | only in WiiMote
      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