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