Refactored wiimote handling, splitting into two separate files.

Also added non-threading support (while it is too slow/too high
latency it's useful for debugging).


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@12781 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2013-05-22 11:28:57 +00:00
parent e45f728008
commit 7ac899ade7
15 changed files with 4776 additions and 4676 deletions

View File

@ -76,6 +76,7 @@ src/input/binding.cpp
src/input/device_manager.cpp src/input/device_manager.cpp
src/input/input_device.cpp src/input/input_device.cpp
src/input/input_manager.cpp src/input/input_manager.cpp
src/input/wiimote.cpp
src/input/wiimote_manager.cpp src/input/wiimote_manager.cpp
src/io/file_manager.cpp src/io/file_manager.cpp
src/io/xml_node.cpp src/io/xml_node.cpp
@ -94,8 +95,8 @@ src/items/projectile_manager.cpp
src/items/rubber_ball.cpp src/items/rubber_ball.cpp
src/items/rubber_band.cpp src/items/rubber_band.cpp
src/items/swatter.cpp src/items/swatter.cpp
src/karts/abstract_kart_animation.cpp
src/karts/abstract_kart.cpp src/karts/abstract_kart.cpp
src/karts/abstract_kart_animation.cpp
src/karts/cannon_animation.cpp src/karts/cannon_animation.cpp
src/karts/controller/ai_base_controller.cpp src/karts/controller/ai_base_controller.cpp
src/karts/controller/ai_properties.cpp src/karts/controller/ai_properties.cpp
@ -185,13 +186,13 @@ src/states_screens/kart_selection.cpp
src/states_screens/main_menu_screen.cpp src/states_screens/main_menu_screen.cpp
src/states_screens/minimal_race_gui.cpp src/states_screens/minimal_race_gui.cpp
src/states_screens/options_screen_audio.cpp src/states_screens/options_screen_audio.cpp
src/states_screens/options_screen_input2.cpp
src/states_screens/options_screen_input.cpp src/states_screens/options_screen_input.cpp
src/states_screens/options_screen_input2.cpp
src/states_screens/options_screen_players.cpp src/states_screens/options_screen_players.cpp
src/states_screens/options_screen_ui.cpp src/states_screens/options_screen_ui.cpp
src/states_screens/options_screen_video.cpp src/states_screens/options_screen_video.cpp
src/states_screens/race_gui_base.cpp
src/states_screens/race_gui.cpp src/states_screens/race_gui.cpp
src/states_screens/race_gui_base.cpp
src/states_screens/race_gui_overworld.cpp src/states_screens/race_gui_overworld.cpp
src/states_screens/race_result_gui.cpp src/states_screens/race_result_gui.cpp
src/states_screens/race_setup_screen.cpp src/states_screens/race_setup_screen.cpp
@ -251,8 +252,8 @@ src/animations/animation_base.hpp
src/animations/ipo.hpp src/animations/ipo.hpp
src/animations/three_d_animation.hpp src/animations/three_d_animation.hpp
src/audio/dummy_sfx.hpp src/audio/dummy_sfx.hpp
src/audio/music_dummy.hpp
src/audio/music.hpp src/audio/music.hpp
src/audio/music_dummy.hpp
src/audio/music_information.hpp src/audio/music_information.hpp
src/audio/music_manager.hpp src/audio/music_manager.hpp
src/audio/music_ogg.hpp src/audio/music_ogg.hpp
@ -260,8 +261,8 @@ src/audio/sfx_base.hpp
src/audio/sfx_buffer.hpp src/audio/sfx_buffer.hpp
src/audio/sfx_manager.hpp src/audio/sfx_manager.hpp
src/audio/sfx_openal.hpp src/audio/sfx_openal.hpp
src/challenges/challenge_data.hpp
src/challenges/challenge.hpp src/challenges/challenge.hpp
src/challenges/challenge_data.hpp
src/challenges/game_slot.hpp src/challenges/game_slot.hpp
src/challenges/unlock_manager.hpp src/challenges/unlock_manager.hpp
src/config/device_config.hpp src/config/device_config.hpp
@ -302,11 +303,11 @@ src/guiengine/scalable_font.hpp
src/guiengine/screen.hpp src/guiengine/screen.hpp
src/guiengine/skin.hpp src/guiengine/skin.hpp
src/guiengine/widget.hpp src/guiengine/widget.hpp
src/guiengine/widgets.hpp
src/guiengine/widgets/bubble_widget.hpp src/guiengine/widgets/bubble_widget.hpp
src/guiengine/widgets/button_widget.hpp src/guiengine/widgets/button_widget.hpp
src/guiengine/widgets/check_box_widget.hpp src/guiengine/widgets/check_box_widget.hpp
src/guiengine/widgets/dynamic_ribbon_widget.hpp src/guiengine/widgets/dynamic_ribbon_widget.hpp
src/guiengine/widgets.hpp
src/guiengine/widgets/icon_button_widget.hpp src/guiengine/widgets/icon_button_widget.hpp
src/guiengine/widgets/label_widget.hpp src/guiengine/widgets/label_widget.hpp
src/guiengine/widgets/list_widget.hpp src/guiengine/widgets/list_widget.hpp
@ -317,9 +318,10 @@ src/guiengine/widgets/spinner_widget.hpp
src/guiengine/widgets/text_box_widget.hpp src/guiengine/widgets/text_box_widget.hpp
src/input/binding.hpp src/input/binding.hpp
src/input/device_manager.hpp src/input/device_manager.hpp
src/input/input_device.hpp
src/input/input.hpp src/input/input.hpp
src/input/input_device.hpp
src/input/input_manager.hpp src/input/input_manager.hpp
src/input/wiimote.hpp
src/input/wiimote_manager.hpp src/input/wiimote_manager.hpp
src/io/file_manager.hpp src/io/file_manager.hpp
src/io/xml_node.hpp src/io/xml_node.hpp
@ -339,8 +341,8 @@ src/items/projectile_manager.hpp
src/items/rubber_ball.hpp src/items/rubber_ball.hpp
src/items/rubber_band.hpp src/items/rubber_band.hpp
src/items/swatter.hpp src/items/swatter.hpp
src/karts/abstract_kart_animation.hpp
src/karts/abstract_kart.hpp src/karts/abstract_kart.hpp
src/karts/abstract_kart_animation.hpp
src/karts/cannon_animation.hpp src/karts/cannon_animation.hpp
src/karts/controller/ai_base_controller.hpp src/karts/controller/ai_base_controller.hpp
src/karts/controller/ai_properties.hpp src/karts/controller/ai_properties.hpp
@ -351,8 +353,8 @@ src/karts/controller/player_controller.hpp
src/karts/controller/skidding_ai.hpp src/karts/controller/skidding_ai.hpp
src/karts/explosion_animation.hpp src/karts/explosion_animation.hpp
src/karts/ghost_kart.hpp src/karts/ghost_kart.hpp
src/karts/kart_gfx.hpp
src/karts/kart.hpp src/karts/kart.hpp
src/karts/kart_gfx.hpp
src/karts/kart_model.hpp src/karts/kart_model.hpp
src/karts/kart_properties.hpp src/karts/kart_properties.hpp
src/karts/kart_properties_manager.hpp src/karts/kart_properties_manager.hpp
@ -443,13 +445,13 @@ src/states_screens/kart_selection.hpp
src/states_screens/main_menu_screen.hpp src/states_screens/main_menu_screen.hpp
src/states_screens/minimal_race_gui.hpp src/states_screens/minimal_race_gui.hpp
src/states_screens/options_screen_audio.hpp src/states_screens/options_screen_audio.hpp
src/states_screens/options_screen_input2.hpp
src/states_screens/options_screen_input.hpp src/states_screens/options_screen_input.hpp
src/states_screens/options_screen_input2.hpp
src/states_screens/options_screen_players.hpp src/states_screens/options_screen_players.hpp
src/states_screens/options_screen_ui.hpp src/states_screens/options_screen_ui.hpp
src/states_screens/options_screen_video.hpp src/states_screens/options_screen_video.hpp
src/states_screens/race_gui_base.hpp
src/states_screens/race_gui.hpp src/states_screens/race_gui.hpp
src/states_screens/race_gui_base.hpp
src/states_screens/race_gui_overworld.hpp src/states_screens/race_gui_overworld.hpp
src/states_screens/race_result_gui.hpp src/states_screens/race_result_gui.hpp
src/states_screens/race_setup_screen.hpp src/states_screens/race_setup_screen.hpp
@ -479,8 +481,8 @@ src/tracks/check_sphere.hpp
src/tracks/check_structure.hpp src/tracks/check_structure.hpp
src/tracks/graph_node.hpp src/tracks/graph_node.hpp
src/tracks/lod_node_loader.hpp src/tracks/lod_node_loader.hpp
src/tracks/quad_graph.hpp
src/tracks/quad.hpp src/tracks/quad.hpp
src/tracks/quad_graph.hpp
src/tracks/quad_set.hpp src/tracks/quad_set.hpp
src/tracks/terrain_info.hpp src/tracks/terrain_info.hpp
src/tracks/track.hpp src/tracks/track.hpp

View File

@ -310,14 +310,15 @@ void GamepadConfig::setDefaultBinds ()
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
GamepadConfig::GamepadConfig ( const std::string name, GamepadConfig::GamepadConfig ( const std::string &name,
const int axis_count, const int axis_count,
const int btnCount ) : DeviceConfig( DEVICE_CONFIG_TYPE_GAMEPAD ) const int button_count )
: DeviceConfig( DEVICE_CONFIG_TYPE_GAMEPAD )
{ {
m_name = name; m_name = name;
m_axis_count = axis_count; m_axis_count = axis_count;
m_button_count = btnCount; m_button_count = button_count;
m_plugged = 0; m_plugged = 0;
setDefaultBinds(); setDefaultBinds();
} }

View File

@ -159,21 +159,28 @@ class GamepadConfig : public DeviceConfig
{ {
private: private:
/** Number of axis this device has. */
int m_axis_count; int m_axis_count;
/** Number of buttons this device has. */
int m_button_count; int m_button_count;
public: public:
irr::core::stringw toString (); irr::core::stringw toString ();
int getAxisCount() const { return m_axis_count; };
int getButtonCount() const { return m_button_count; };
void serialize (std::ofstream& stream); void serialize (std::ofstream& stream);
void setDefaultBinds (); void setDefaultBinds ();
GamepadConfig (irr::io::IrrXMLReader* xml); GamepadConfig (irr::io::IrrXMLReader* xml);
GamepadConfig (const std::string name, GamepadConfig (const std::string &name,
const int axis_count, const int axis_count=0,
const int btnCount); const int button_ount=0);
// ------------------------------------------------------------------------
/** Sets the number of buttons this device has. */
void setNumberOfButtons(int count) { m_button_count = count; }
// ------------------------------------------------------------------------
/** Sets the number of axis this device has. */
void setNumberOfAxis(int count) { m_axis_count = count; }
// ~GamepadConfig(); // ~GamepadConfig();
}; };

File diff suppressed because it is too large Load Diff

View File

@ -864,6 +864,9 @@
<ClCompile Include="..\..\tracks\track_object_presentation.cpp"> <ClCompile Include="..\..\tracks\track_object_presentation.cpp">
<Filter>Source Files\tracks</Filter> <Filter>Source Files\tracks</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\input\wiimote.cpp">
<Filter>Source Files\input</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\main_loop.hpp"> <ClInclude Include="..\..\main_loop.hpp">
@ -1655,5 +1658,8 @@
<ClInclude Include="..\..\tracks\track_object_presentation.hpp"> <ClInclude Include="..\..\tracks\track_object_presentation.hpp">
<Filter>Header Files\tracks</Filter> <Filter>Header Files\tracks</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\input\wiimote.hpp">
<Filter>Header Files\input</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

File diff suppressed because it is too large Load Diff

View File

@ -864,6 +864,9 @@
<ClCompile Include="..\..\tracks\track_object_presentation.cpp"> <ClCompile Include="..\..\tracks\track_object_presentation.cpp">
<Filter>Source Files\tracks</Filter> <Filter>Source Files\tracks</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\input\wiimote.cpp">
<Filter>Source Files\input</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\main_loop.hpp"> <ClInclude Include="..\..\main_loop.hpp">
@ -1655,5 +1658,8 @@
<ClInclude Include="..\..\tracks\track_object_presentation.hpp"> <ClInclude Include="..\..\tracks\track_object_presentation.hpp">
<Filter>Header Files\tracks</Filter> <Filter>Header Files\tracks</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\input\wiimote.hpp">
<Filter>Header Files\input</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

File diff suppressed because it is too large Load Diff

View File

@ -49,7 +49,6 @@ bool DeviceManager::initialize()
GamePadDevice *gamepadDevice = NULL; GamePadDevice *gamepadDevice = NULL;
m_map_fire_to_select = false; m_map_fire_to_select = false;
bool created = false; bool created = false;
int numGamepads;
// Shutdown in case the device manager is being re-initialized // Shutdown in case the device manager is being re-initialized
@ -83,19 +82,19 @@ bool DeviceManager::initialize()
printf("Initializing gamepad support.\n"); printf("Initializing gamepad support.\n");
irr_driver->getDevice()->activateJoysticks(m_irrlicht_gamepads); irr_driver->getDevice()->activateJoysticks(m_irrlicht_gamepads);
numGamepads = m_irrlicht_gamepads.size(); int num_gamepads = m_irrlicht_gamepads.size();
if(UserConfigParams::logMisc()) if(UserConfigParams::logMisc())
{ {
printf("Irrlicht reports %d gamepads are attached to the system.\n", printf("Irrlicht reports %d gamepads are attached to the system.\n",
numGamepads); num_gamepads);
} }
// Create GamePadDevice for each physical gamepad and find a GamepadConfig to match // Create GamePadDevice for each physical gamepad and find a GamepadConfig to match
for (int id = 0; id < numGamepads; id++) for (int id = 0; id < num_gamepads; id++)
{ {
core::stringc name = m_irrlicht_gamepads[id].Name.c_str(); core::stringc name = m_irrlicht_gamepads[id].Name;
// Some linux systems report a disk accelerometer as a gamepad, skip that // Some linux systems report a disk accelerometer as a gamepad, skip that
if (name.find("LIS3LV02DL") != -1) continue; if (name.find("LIS3LV02DL") != -1) continue;
@ -103,9 +102,9 @@ bool DeviceManager::initialize()
#ifdef WIN32 #ifdef WIN32
// On Windows, unless we use DirectInput, all gamepads are given the // On Windows, unless we use DirectInput, all gamepads are given the
// same name ('microsoft pc-joystick driver'). This makes configuration // same name ('microsoft pc-joystick driver'). This makes configuration
// totally useless, so append an ID to the name. We can't test for the // totally useless, so append an ID to the name. We can't test for the
// name, since the name is even translated. // name, since the name is even translated.
name = name + " " + StringUtils::toString(id).c_str(); name = name + " " + StringUtils::toString(id).c_str();
#endif #endif
if (UserConfigParams::logMisc()) if (UserConfigParams::logMisc())
@ -180,10 +179,12 @@ GamePadDevice* DeviceManager::getGamePadFromIrrID(const int id)
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
/** /**
* Check if we already have a config object for gamepad 'irr_id' as reported by irrLicht * Check if we already have a config object for gamepad 'irr_id' as reported by
* If no, create one. Returns true if new configuration was created, otherwise false. * irrLicht, If no, create one. Returns true if new configuration was created,
* otherwise false.
*/ */
bool DeviceManager::getConfigForGamepad(const int irr_id, const core::stringc& name, GamepadConfig **config) bool DeviceManager::getConfigForGamepad(const int irr_id, const core::stringc& name,
GamepadConfig **config)
{ {
bool found = false; bool found = false;
bool configCreated = false; bool configCreated = false;
@ -210,9 +211,8 @@ bool DeviceManager::getConfigForGamepad(const int irr_id, const core::stringc& n
#ifdef ENABLE_WIIUSE #ifdef ENABLE_WIIUSE
else // Wiimotes have a higher ID and do not refer to m_irrlicht_gamepads else // Wiimotes have a higher ID and do not refer to m_irrlicht_gamepads
{ {
*config = new GamepadConfig( name.c_str(), // The Wiimote manager will set number of buttons and axis
WIIMOTE_AXES, *config = new GamepadConfig(name.c_str());
WIIMOTE_BUTTONS );
} }
#endif #endif
@ -430,7 +430,7 @@ InputDevice* DeviceManager::getLatestUsedDevice()
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void DeviceManager::clearLatestUsedDevice() void DeviceManager::clearLatestUsedDevice()
{ {
m_latest_used_device = NULL; m_latest_used_device = NULL;
} // clearLatestUsedDevice } // clearLatestUsedDevice
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -56,6 +56,8 @@ private:
PtrVector<GamePadDevice, HOLD> m_gamepads; PtrVector<GamePadDevice, HOLD> m_gamepads;
PtrVector<KeyboardConfig, HOLD> m_keyboard_configs; PtrVector<KeyboardConfig, HOLD> m_keyboard_configs;
PtrVector<GamepadConfig, HOLD> m_gamepad_configs; PtrVector<GamepadConfig, HOLD> m_gamepad_configs;
/** The list of all joysticks that were found and activated. */
core::array<SJoystickInfo> m_irrlicht_gamepads; core::array<SJoystickInfo> m_irrlicht_gamepads;
InputDevice* m_latest_used_device; InputDevice* m_latest_used_device;
PlayerAssignMode m_assign_mode; PlayerAssignMode m_assign_mode;

View File

@ -75,7 +75,7 @@ bool KeyboardDevice::processAndMapInput(const int id,
GamePadDevice::GamePadDevice(const int irrIndex, const std::string name, GamePadDevice::GamePadDevice(const int irrIndex, const std::string name,
const int axis_count, const int btnAmount, const int axis_count, const int button_count,
GamepadConfig *configuration) GamepadConfig *configuration)
{ {
m_type = DT_GAMEPAD; m_type = DT_GAMEPAD;
@ -86,7 +86,7 @@ GamePadDevice::GamePadDevice(const int irrIndex, const std::string name,
m_prevAxisDirections = new Input::AxisDirection[axis_count]; m_prevAxisDirections = new Input::AxisDirection[axis_count];
m_prevAxisValue = new int[axis_count]; m_prevAxisValue = new int[axis_count];
m_axis_ok = new bool[axis_count]; m_axis_ok = new bool[axis_count];
m_button_count = btnAmount; m_button_count = button_count;
m_index = irrIndex; m_index = irrIndex;
m_name = name; m_name = name;

180
src/input/wiimote.cpp Normal file
View File

@ -0,0 +1,180 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifdef ENABLE_WIIUSE
#include "input/wiimote.hpp"
#include "input/device_manager.hpp"
#include "utils/string_utils.hpp"
#include "wiiuse.h"
Wiimote::Wiimote(wiimote_t* wiimote_handle, int wiimote_id,
GamepadConfig* gamepad_config)
{
m_wiimote_handle = wiimote_handle;
m_wiimote_id = wiimote_id;
resetIrrEvent();
m_connected = true;
// Create the corresponding gamepad device
irr::core::stringc gamepad_name = irr::core::stringc("Wiimote ") +
StringUtils::toString(wiimote_id).c_str();
gamepad_config->setPlugged();
// Determine number of bits in the bit mask of all buttons.
int button_count = (int)( log((float)WIIMOTE_BUTTON_ALL) / log(2.0f))+1;
m_gamepad_device = new GamePadDevice(getIrrId(),
gamepad_name.c_str(),
/*num axes*/ 1,
button_count,
gamepad_config );
DeviceManager* device_manager = input_manager->getDeviceList();
device_manager->addGamepad(m_gamepad_device);
} // Wiimote
// ----------------------------------------------------------------------------
Wiimote::~Wiimote()
{
} // ~Wiimote
// -----------------------------------------------------------------------------
void Wiimote::resetIrrEvent()
{
irr::SEvent &event = m_irr_event.getData();
event.EventType = irr::EET_JOYSTICK_INPUT_EVENT;
for(int i=0 ; i < irr::SEvent::SJoystickEvent::NUMBER_OF_AXES ; i++)
event.JoystickEvent.Axis[i] = 0;
event.JoystickEvent.Joystick = getIrrId();
event.JoystickEvent.POV = 65535;
event.JoystickEvent.ButtonStates = 0;
} // resetIrrEvent
// -----------------------------------------------------------------------------
/** Called from the update thread: takes the wiimote state and
*/
void Wiimote::update()
{
#ifdef DEBUG
if(UserConfigParams::m_wiimote_debug)
{
Log::verbose("wiimote", "pitch: %f yaw %f roll %f",
m_wiimote_handle->orient.pitch,
m_wiimote_handle->orient.yaw,
m_wiimote_handle->orient.roll);
}
#endif
float normalized_angle = -m_wiimote_handle->orient.pitch / UserConfigParams::m_wiimote_max;
if(normalized_angle<-1.0f)
normalized_angle = -1.0f;
else if(normalized_angle>1.0f)
normalized_angle = 1.0f;
// Shape the curve that determines steering depending on wiimote angle.
// The wiimote value is already normalized to be in [-1,1]. Now use a
// weighted linear combination to compute the steering value used in game.
float w1 = UserConfigParams::m_wiimote_weight_linear;
float w2 = UserConfigParams::m_wiimote_weight_square;
float wa = UserConfigParams::m_wiimote_weight_asin;
float ws = UserConfigParams::m_wiimote_weight_sin;
const float sign = normalized_angle >= 0.0f ? 1.0f : -1.0f;
const float normalized_angle_2 = w1 * normalized_angle
+ w2 * sign*normalized_angle*normalized_angle
+ wa * asin(normalized_angle)*(2.0f/M_PI)
+ ws * sin(normalized_angle*(M_PI/2.0f));
const float JOYSTICK_ABS_MAX_ANGLE = 32766.0f;
const float angle = normalized_angle_2 * JOYSTICK_ABS_MAX_ANGLE;
m_irr_event.lock();
{
irr::SEvent::SJoystickEvent &ev = m_irr_event.getData().JoystickEvent;
ev.Axis[SEvent::SJoystickEvent::AXIS_X] =
(irr::s16)(irr::core::clamp(angle, -JOYSTICK_ABS_MAX_ANGLE,
+JOYSTICK_ABS_MAX_ANGLE));
// --------------------- Wiimote buttons --------------------
// Copy the wiimote button structure, but mask out the non-button
// bits (4 bits of the button structure are actually bits for the
// accelerator).
ev.ButtonStates = m_wiimote_handle->btns & WIIMOTE_BUTTON_ALL;
}
m_irr_event.unlock();
#ifdef DEBUG
if(UserConfigParams::m_wiimote_debug)
printDebugInfo();
#endif
} // update
// ----------------------------------------------------------------------------
/** Prints debug information to Log::verbose about accelerometer and button
* states.
*/
void Wiimote::printDebugInfo() const
{
struct WiimoteAction
{
int wiimote_action_id;
const char* wiimote_action_name;
}; // struct WiimoteAction
static WiimoteAction wiimote_actions[] = {
{WIIMOTE_BUTTON_LEFT, "WIIMOTE_BUTTON_LEFT" },
{WIIMOTE_BUTTON_RIGHT, "WIIMOTE_BUTTON_RIGHT"},
{WIIMOTE_BUTTON_UP, "WIIMOTE_BUTTON_UP" },
{WIIMOTE_BUTTON_DOWN, "WIIMOTE_BUTTON_DOWN" },
{WIIMOTE_BUTTON_A, "WIIMOTE_BUTTON_A" },
{WIIMOTE_BUTTON_B, "WIIMOTE_BUTTON_B" },
{WIIMOTE_BUTTON_PLUS, "WIIMOTE_BUTTON_PLUS" },
{WIIMOTE_BUTTON_MINUS, "WIIMOTE_BUTTON_MINUS"},
{WIIMOTE_BUTTON_ONE, "WIIMOTE_BUTTON_ONE" },
{WIIMOTE_BUTTON_TWO, "WIIMOTE_BUTTON_TWO" },
{WIIMOTE_BUTTON_HOME, "WIIMOTE_BUTTON_HOME" },
}; // wiimote_actions
const int count = sizeof(wiimote_actions)/sizeof(WiimoteAction);
for(unsigned int i=0 ; i<count; i++)
{
if(IS_PRESSED(m_wiimote_handle, wiimote_actions[i].wiimote_action_id))
{
Log::verbose("wiimote", "%d: pressed button %s -> button id: %d",
m_wiimote_id, wiimote_actions[i].wiimote_action_name,
i);
}
} // for i < count
} // printDebugInfo
// ----------------------------------------------------------------------------
/** Thread-safe reading of the last updated event
*/
irr::SEvent Wiimote::getIrrEvent()
{
return m_irr_event.getAtomic();
} // getIrrEvent
#endif // ENABLE_WIIUSE

87
src/input/wiimote.hpp Normal file
View File

@ -0,0 +1,87 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef WIIMOTE_HPP
#define WIIMOTE_HPP
#ifdef ENABLE_WIIUSE
#include "utils/synchronised.hpp"
#include "IEventReceiver.h"
struct wiimote_t;
class GamepadConfig;
class GamePadDevice;
/** Wiimote device class */
class Wiimote
{
private:
/** Offset for wiimote irrlicht gamepads ids, to make sure any wiimote
* can be identified by having this or a larger id. */
static const int WIIMOTE_START_IRR_ID = 32;
/** Handle to the corresponding WiiUse wiimote handle */
wiimote_t* m_wiimote_handle;
/** Index of this element the arrays of wiimotes */
int m_wiimote_id;
/** Corresponding gamepad managed by the DeviceManager */
GamePadDevice* m_gamepad_device;
/** Corresponding Irrlicht gamepad event */
Synchronised<irr::SEvent> m_irr_event;
/** Whether the wiimote received a "disconnected" event */
bool m_connected;
void resetIrrEvent();
void printDebugInfo() const;
public:
/** Resets internal state and creates the corresponding gamepad device */
Wiimote(wiimote_t* wiimote_handle, int wiimote_id,
GamepadConfig* gamepad_config);
~Wiimote();
/** To be called when the wiimote becomes unused */
void cleanup();
void update();
irr::SEvent getIrrEvent();
// -----------------------------------------------------------------------------
/** Returns the wiiuse handle of this wiimote. */
wiimote_t* getWiimoteHandle() const { return m_wiimote_handle; }
// -----------------------------------------------------------------------------
/** Returns true if this wiimote is connected. */
bool isConnected() const { return m_connected; }
// -----------------------------------------------------------------------------
/** Sets the connection state of this wiimote. */
void setConnected(bool connected) { m_connected=connected; }
// -----------------------------------------------------------------------------
/** Returns the irrlicht id for this wiimote. The wiimote ids have a higher
* index than any gamepad reported by irrlicht.*/
int Wiimote::getIrrId() { return m_wiimote_id + WIIMOTE_START_IRR_ID; }
}; // class Wiimote
#endif
#endif // WIIMOTE_HPP

View File

@ -24,6 +24,7 @@
#include "guiengine/modaldialog.hpp" #include "guiengine/modaldialog.hpp"
#include "input/input_manager.hpp" #include "input/input_manager.hpp"
#include "input/device_manager.hpp" #include "input/device_manager.hpp"
#include "input/wiimote.hpp"
#include "utils/string_utils.hpp" #include "utils/string_utils.hpp"
#include "utils/translation.hpp" #include "utils/translation.hpp"
@ -31,233 +32,18 @@
WiimoteManager* wiimote_manager; WiimoteManager* wiimote_manager;
const int WIIMOTE_AXES = 1; // only use one axis, for turning
const int WIIMOTE_BUTTONS = 12; // A, B, left, right, top, bottom, 1, 2, (+), (-), home
bool WiimoteManager::m_enabled = false; bool WiimoteManager::m_enabled = false;
/** Irrlicht device IDs for the wiimotes start at this value */ /** Irrlicht device IDs for the wiimotes start at this value */
static const int WIIMOTE_START_IRR_ID = 32; static const int WIIMOTE_START_IRR_ID = 32;
static const float JOYSTICK_ABS_MAX_ANGLE = 32766.0f;
// ============================ Helper functions ============================
// -----------------------------------------------------------------------------
static int wiimoteIdToIrrId(int wiimote_id)
{
return wiimote_id + WIIMOTE_START_IRR_ID;
} // wiimoteIdToIrrId
// -----------------------------------------------------------------------------
static void resetIrrEvent(irr::SEvent* event, int irr_id)
{
event->EventType = irr::EET_JOYSTICK_INPUT_EVENT;
for(int i=0 ; i < SEvent::SJoystickEvent::NUMBER_OF_AXES ; i++)
event->JoystickEvent.Axis[i] = 0;
event->JoystickEvent.Joystick = irr_id;
event->JoystickEvent.POV = 65535;
event->JoystickEvent.ButtonStates = 0;
} // resetIrrEvent
// -----------------------------------------------------------------------------
struct WiimoteAction
{
int button_id;
int wiimote_action_id;
const char* wiimote_action_name;
}; // struct WiimoteAction
static WiimoteAction wiimote_actions[] = {
{0, WIIMOTE_BUTTON_LEFT, "WIIMOTE_BUTTON_LEFT"},
{1, WIIMOTE_BUTTON_RIGHT, "WIIMOTE_BUTTON_RIGHT"},
{2, WIIMOTE_BUTTON_UP, "WIIMOTE_BUTTON_UP"},
{3, WIIMOTE_BUTTON_DOWN, "WIIMOTE_BUTTON_DOWN"},
{4, WIIMOTE_BUTTON_A, "WIIMOTE_BUTTON_A"},
{5, WIIMOTE_BUTTON_B, "WIIMOTE_BUTTON_B"},
{6, WIIMOTE_BUTTON_PLUS, "WIIMOTE_BUTTON_PLUS"},
{7, WIIMOTE_BUTTON_MINUS, "WIIMOTE_BUTTON_MINUS"},
{8, WIIMOTE_BUTTON_ONE, "WIIMOTE_BUTTON_ONE"},
{9, WIIMOTE_BUTTON_TWO, "WIIMOTE_BUTTON_TWO"},
{10, WIIMOTE_BUTTON_HOME, "WIIMOTE_BUTTON_HOME"},
}; // wiimote_actions
static int getButtonId(int wiimote_action_id)
{
for(unsigned int i=0 ; i < sizeof(wiimote_actions)/sizeof(WiimoteAction) ; i++)
if(wiimote_actions[i].wiimote_action_id == wiimote_action_id)
return wiimote_actions[i].button_id;
assert(false && "shouldn't happen");
return -1;
} // getButtonId
// -----------------------------------------------------------------------------
static void setWiimoteBindings(GamepadConfig* gamepad_config)
{
gamepad_config->setBinding(PA_STEER_LEFT, Input::IT_STICKMOTION, 0, Input::AD_NEGATIVE);
gamepad_config->setBinding(PA_STEER_RIGHT, Input::IT_STICKMOTION, 0, Input::AD_POSITIVE);
gamepad_config->setBinding(PA_ACCEL, Input::IT_STICKBUTTON, getButtonId(WIIMOTE_BUTTON_TWO));
gamepad_config->setBinding(PA_BRAKE, Input::IT_STICKBUTTON, getButtonId(WIIMOTE_BUTTON_ONE));
gamepad_config->setBinding(PA_FIRE, Input::IT_STICKBUTTON, getButtonId(WIIMOTE_BUTTON_RIGHT));
gamepad_config->setBinding(PA_NITRO, Input::IT_STICKBUTTON, getButtonId(WIIMOTE_BUTTON_UP));
gamepad_config->setBinding(PA_DRIFT, Input::IT_STICKBUTTON, getButtonId(WIIMOTE_BUTTON_B));
gamepad_config->setBinding(PA_RESCUE, Input::IT_STICKBUTTON, getButtonId(WIIMOTE_BUTTON_PLUS));
gamepad_config->setBinding(PA_LOOK_BACK, Input::IT_STICKBUTTON, getButtonId(WIIMOTE_BUTTON_DOWN));
gamepad_config->setBinding(PA_PAUSE_RACE, Input::IT_STICKBUTTON, getButtonId(WIIMOTE_BUTTON_HOME));
gamepad_config->setBinding(PA_MENU_UP, Input::IT_STICKBUTTON, getButtonId(WIIMOTE_BUTTON_RIGHT));
gamepad_config->setBinding(PA_MENU_DOWN, Input::IT_STICKBUTTON, getButtonId(WIIMOTE_BUTTON_LEFT));
gamepad_config->setBinding(PA_MENU_LEFT, Input::IT_STICKBUTTON, getButtonId(WIIMOTE_BUTTON_UP));
gamepad_config->setBinding(PA_MENU_RIGHT, Input::IT_STICKBUTTON, getButtonId(WIIMOTE_BUTTON_DOWN));
gamepad_config->setBinding(PA_MENU_SELECT, Input::IT_STICKBUTTON, getButtonId(WIIMOTE_BUTTON_TWO));
gamepad_config->setBinding(PA_MENU_CANCEL, Input::IT_STICKBUTTON, getButtonId(WIIMOTE_BUTTON_ONE));
} // setWiimoteBindings
// ============================ Wiimote device implementation ============================
Wiimote::Wiimote()
{
m_wiimote_handle = NULL;
m_wiimote_id = -1;
m_gamepad_device = NULL;
resetIrrEvent(&m_irr_event, 0);
m_connected = false;
pthread_mutex_init(&m_event_mutex, NULL);
} // Wiimote
// ----------------------------------------------------------------------------
Wiimote::~Wiimote()
{
pthread_mutex_destroy(&m_event_mutex);
} // ~Wiimote
// -----------------------------------------------------------------------------
/** Resets internal state and creates the corresponding gamepad device */
void Wiimote::init(wiimote_t* wiimote_handle, int wiimote_id, GamepadConfig* gamepad_config)
{
m_wiimote_handle = wiimote_handle;
m_wiimote_id = wiimote_id;
int irr_id = wiimoteIdToIrrId(wiimote_id);
resetIrrEvent(&m_irr_event, irr_id);
m_connected = true;
// Create the corresponding gamepad device
core::stringc gamepad_name = core::stringc("Wiimote ") + StringUtils::toString(wiimote_id).c_str();
DeviceManager* device_manager = input_manager->getDeviceList();
gamepad_config->setPlugged();
m_gamepad_device = new GamePadDevice(irr_id,
gamepad_name.c_str(),
WIIMOTE_AXES,
WIIMOTE_BUTTONS,
gamepad_config );
device_manager->addGamepad(m_gamepad_device);
} // init
// -----------------------------------------------------------------------------
/** Called from the update thread: updates the Irrlicht event from the wiimote state */
void Wiimote::updateIrrEvent()
{
pthread_mutex_lock(&m_event_mutex);
// Simulate an Irrlicht joystick event
resetIrrEvent(&m_irr_event, wiimoteIdToIrrId(m_wiimote_id));
#ifdef DEBUG
if(UserConfigParams::m_wiimote_debug)
{
Log::verbose("wiimote", "pitch: %f yaw %f roll %f",
m_wiimote_handle->orient.pitch,
m_wiimote_handle->orient.yaw,
m_wiimote_handle->orient.roll);
}
#endif
float normalized_angle = -m_wiimote_handle->orient.pitch / UserConfigParams::m_wiimote_max;
if(normalized_angle<-1.0f)
normalized_angle = -1.0f;
else if(normalized_angle>1.0f)
normalized_angle = 1.0f;
// Shape the curve that determines steering depending on wiimote angle.
// The wiimote value is already normalized to be in [-1,1]. Now use a
// weighted linear combination to compute the steering value used in game.
float w1 = UserConfigParams::m_wiimote_weight_linear;
float w2 = UserConfigParams::m_wiimote_weight_square;
float wa = UserConfigParams::m_wiimote_weight_asin;
float ws = UserConfigParams::m_wiimote_weight_sin;
const float sign = normalized_angle >= 0.0f ? 1.0f : -1.0f;
const float normalized_angle_2 = w1 * normalized_angle
+ w2 * sign*normalized_angle * normalized_angle
+ wa * asin(normalized_angle)*(2.0f/M_PI)
+ ws * sin(normalized_angle*(M_PI/2.0f));
const float angle = normalized_angle_2 * JOYSTICK_ABS_MAX_ANGLE;
m_irr_event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_X] =
(irr::s16)(irr::core::clamp(angle, -JOYSTICK_ABS_MAX_ANGLE, +JOYSTICK_ABS_MAX_ANGLE));
// --------------------- Wiimote buttons --------------------
// Send button states
for(unsigned int i=0 ; i < sizeof(wiimote_actions)/sizeof(WiimoteAction) ; i++)
{
if(IS_PRESSED(m_wiimote_handle, wiimote_actions[i].wiimote_action_id))
{
#ifdef DEBUG
if(UserConfigParams::m_wiimote_debug)
Log::verbose("wiimote", "%d: pressed button %s -> button id: %d\n",
m_wiimote_id,
wiimote_actions[i].wiimote_action_name,
wiimote_actions[i].button_id);
#endif
m_irr_event.JoystickEvent.ButtonStates |= (1<<(wiimote_actions[i].button_id));
}
}
// ------------------ Nunchuk ----------------------
/* if (m_wiimote_handle->exp.type == EXP_NUNCHUK)
{
struct nunchuk_t* nc = (nunchuk_t*)&m_wiimote_handle->exp.nunchuk;
if (IS_PRESSED(nc, NUNCHUK_BUTTON_C))
{
printf("DEBUG: C\n");
m_irr_event.JoystickEvent.ButtonStates |= (1<<12);
}
if (IS_PRESSED(nc, NUNCHUK_BUTTON_Z))
{
printf("DEBUG: Z\n");
m_irr_event.JoystickEvent.ButtonStates |= (1<<13);
}
printf("nunchuk roll = %f\n", nc->orient.roll);
printf("nunchuk pitch = %f\n", nc->orient.pitch);
printf("nunchuk yaw = %f\n", nc->orient.yaw);
printf("nunchuk joystick angle: %f\n", nc->js.ang);
printf("nunchuk joystick magnitude: %f\n", nc->js.mag);
}
*/
pthread_mutex_unlock(&m_event_mutex);
} // updateIrrEvent
// ----------------------------------------------------------------------------
irr::SEvent Wiimote::getIrrEvent()
{
irr::SEvent event;
pthread_mutex_lock(&m_event_mutex);
event = m_irr_event;
pthread_mutex_unlock(&m_event_mutex);
return event;
} // getIrrEvent
// ============================ Wiimote manager implementation ============================
WiimoteManager::WiimoteManager() WiimoteManager::WiimoteManager()
{ {
m_all_wiimote_handles = NULL; m_all_wiimote_handles = NULL;
m_nb_wiimotes = 0; #ifdef WIIMOTE_THREADING
m_shut = false; m_shut = false;
#endif
} // WiimoteManager } // WiimoteManager
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -287,10 +73,10 @@ void WiimoteManager::launchDetection(int timeout)
return; return;
// Try to connect to all found wiimotes // Try to connect to all found wiimotes
m_nb_wiimotes = wiiuse_connect(m_all_wiimote_handles, nb_found_wiimotes); int nb_wiimotes = wiiuse_connect(m_all_wiimote_handles, nb_found_wiimotes);
// Couldn't connect to any wiimote? // Couldn't connect to any wiimote?
if(m_nb_wiimotes == 0) if(nb_wiimotes == 0)
return; return;
// --------------------------------------------------- // ---------------------------------------------------
@ -298,149 +84,195 @@ void WiimoteManager::launchDetection(int timeout)
DeviceManager* device_manager = input_manager->getDeviceList(); DeviceManager* device_manager = input_manager->getDeviceList();
GamepadConfig* gamepad_config = NULL; GamepadConfig* gamepad_config = NULL;
device_manager->getConfigForGamepad(WIIMOTE_START_IRR_ID, "Wiimote", &gamepad_config); device_manager->getConfigForGamepad(WIIMOTE_START_IRR_ID, "Wiimote",
&gamepad_config);
int num_buttons = (int)( log((float)WIIMOTE_BUTTON_ALL) / log(2.0f))+1;
gamepad_config->setNumberOfButtons(num_buttons);
gamepad_config->setNumberOfAxis(1);
setWiimoteBindings(gamepad_config); setWiimoteBindings(gamepad_config);
// Initialize all Wiimotes, which in turn create their associated GamePadDevices // Initialize all Wiimotes, which in turn create their
for(int i=0 ; i < m_nb_wiimotes ; i++) // associated GamePadDevices
for(int i=0 ; i < nb_wiimotes ; i++)
{ {
m_wiimotes[i].init(m_all_wiimote_handles[i], i, gamepad_config); m_wiimotes.push_back(new Wiimote(m_all_wiimote_handles[i], i,
gamepad_config ));
} // end for } // end for
// --------------------------------------------------- // ---------------------------------------------------
// Set the LEDs and rumble for 0.2s // Set the LEDs and rumble for 0.2s
int leds[] = {WIIMOTE_LED_1, WIIMOTE_LED_2, WIIMOTE_LED_3, WIIMOTE_LED_4}; int leds[] = {WIIMOTE_LED_1, WIIMOTE_LED_2, WIIMOTE_LED_3, WIIMOTE_LED_4};
for(int i=0 ; i < m_nb_wiimotes ; i++) for(unsigned int i=0 ; i < m_wiimotes.size(); i++)
{ {
wiimote_t* wiimote_handle = m_wiimotes[i].getWiimoteHandle(); wiimote_t* wiimote_handle = m_wiimotes[i]->getWiimoteHandle();
wiiuse_set_leds(wiimote_handle, leds[i]); wiiuse_set_leds(wiimote_handle, leds[i]);
wiiuse_rumble(wiimote_handle, 1); wiiuse_rumble(wiimote_handle, 1);
} }
irr_driver->getDevice()->sleep(200); irr_driver->getDevice()->sleep(200);
for(int i=0 ; i < m_nb_wiimotes ; i++) for(unsigned int i=0 ; i < m_wiimotes.size(); i++)
{ {
wiimote_t* wiimote_handle = m_wiimotes[i].getWiimoteHandle(); wiimote_t* wiimote_handle = m_wiimotes[i]->getWiimoteHandle();
wiiuse_rumble(wiimote_handle, 0); wiiuse_rumble(wiimote_handle, 0);
} }
// TODO: only enable accelerometer during race
enableAccelerometer(true);
// --------------------------------------------------- // ---------------------------------------------------
// Launch the update thread // Launch the update thread
#ifdef WIIMOTE_THREADING
m_shut = false; m_shut = false;
pthread_create(&m_thread, NULL, &threadFuncWrapper, this); pthread_create(&m_thread, NULL, &threadFuncWrapper, this);
#endif
} // launchDetection } // launchDetection
// ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Determines the button number based on the bitmask of a button. E.g.
* 0x0004 (= 00100_2) is converted into 3.
*/
int getButton(int n)
{
return (int)(log((float)n)/log(2.0f));
} // getButton
// ----------------------------------------------------------------------------
/** Defines the key bindings for a wiimote for the device manager.
* \param gamepad_config The configuration to be defined.
*/
void WiimoteManager::setWiimoteBindings(GamepadConfig* gamepad_config)
{
gamepad_config->setBinding(PA_STEER_LEFT, Input::IT_STICKMOTION, 0, Input::AD_NEGATIVE);
gamepad_config->setBinding(PA_STEER_RIGHT, Input::IT_STICKMOTION, 0, Input::AD_POSITIVE);
gamepad_config->setBinding(PA_ACCEL, Input::IT_STICKBUTTON, getButton(WIIMOTE_BUTTON_TWO));
gamepad_config->setBinding(PA_BRAKE, Input::IT_STICKBUTTON, getButton(WIIMOTE_BUTTON_ONE));
gamepad_config->setBinding(PA_FIRE, Input::IT_STICKBUTTON, getButton(WIIMOTE_BUTTON_RIGHT));
gamepad_config->setBinding(PA_NITRO, Input::IT_STICKBUTTON, getButton(WIIMOTE_BUTTON_UP));
gamepad_config->setBinding(PA_DRIFT, Input::IT_STICKBUTTON, getButton(WIIMOTE_BUTTON_B));
gamepad_config->setBinding(PA_RESCUE, Input::IT_STICKBUTTON, getButton(WIIMOTE_BUTTON_PLUS));
gamepad_config->setBinding(PA_LOOK_BACK, Input::IT_STICKBUTTON, getButton(WIIMOTE_BUTTON_DOWN));
gamepad_config->setBinding(PA_PAUSE_RACE, Input::IT_STICKBUTTON, getButton(WIIMOTE_BUTTON_HOME));
gamepad_config->setBinding(PA_MENU_UP, Input::IT_STICKBUTTON, getButton(WIIMOTE_BUTTON_RIGHT));
gamepad_config->setBinding(PA_MENU_DOWN, Input::IT_STICKBUTTON, getButton(WIIMOTE_BUTTON_LEFT));
gamepad_config->setBinding(PA_MENU_LEFT, Input::IT_STICKBUTTON, getButton(WIIMOTE_BUTTON_UP));
gamepad_config->setBinding(PA_MENU_RIGHT, Input::IT_STICKBUTTON, getButton(WIIMOTE_BUTTON_DOWN));
gamepad_config->setBinding(PA_MENU_SELECT, Input::IT_STICKBUTTON, getButton(WIIMOTE_BUTTON_TWO));
gamepad_config->setBinding(PA_MENU_CANCEL, Input::IT_STICKBUTTON, getButton(WIIMOTE_BUTTON_ONE));
} // setWiimoteBindings
// ----------------------------------------------------------------------------
void WiimoteManager::cleanup() void WiimoteManager::cleanup()
{ {
if(m_nb_wiimotes > 0) if(m_wiimotes.size() > 0)
{ {
DeviceManager* device_manager = input_manager->getDeviceList(); DeviceManager* device_manager = input_manager->getDeviceList();
GamePadDevice* first_gamepad_device = device_manager->getGamePadFromIrrID(WIIMOTE_START_IRR_ID); GamePadDevice* first_gamepad_device =
device_manager->getGamePadFromIrrID(WIIMOTE_START_IRR_ID);
assert(first_gamepad_device); assert(first_gamepad_device);
DeviceConfig* gamepad_config = first_gamepad_device->getConfiguration(); DeviceConfig* gamepad_config =
first_gamepad_device->getConfiguration();
assert(gamepad_config); assert(gamepad_config);
// Remove the wiimote configuration -> automatically removes all linked gamepad devices; // Remove the wiimote configuration -> automatically removes all
// linked gamepad devices;
device_manager->deleteConfig(gamepad_config); device_manager->deleteConfig(gamepad_config);
// Shut the update thread // Shut the update thread
#ifdef WIIMOTE_THREADING
m_shut = true; m_shut = true;
pthread_join(m_thread, NULL); pthread_join(m_thread, NULL);
#endif
// Cleanup WiiUse // Cleanup WiiUse
wiiuse_cleanup(m_all_wiimote_handles, MAX_WIIMOTES); wiiuse_cleanup(m_all_wiimote_handles, MAX_WIIMOTES);
} }
for(unsigned int i=0; i<m_wiimotes.size(); i++)
delete m_wiimotes[i];
m_wiimotes.clear();
// Reset // Reset
m_all_wiimote_handles = NULL; m_all_wiimote_handles = NULL;
m_nb_wiimotes = 0; #ifdef WIIMOTE_THREADING
m_shut = false; m_shut = false;
#endif
} // cleanup } // cleanup
// ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void WiimoteManager::update() void WiimoteManager::update()
{ {
for(int i=0 ; i < MAX_WIIMOTES ; i++) #ifndef WIIMOTE_THREADING
threadFunc();
#endif
for(unsigned int i=0 ; i < m_wiimotes.size(); i++)
{ {
if(m_wiimotes[i].isConnected()) irr::SEvent event = m_wiimotes[i]->getIrrEvent();
{ input_manager->input(event);
irr::SEvent event = m_wiimotes[i].getIrrEvent();
input_manager->input(event);
}
} }
} // update } // update
// ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Thread update method - wiimotes state is updated in another thread to avoid latency problems */ /** Enables or disables the accelerometer in wiimotes (to save battery life).
* \param state True if the accelerometer should be enabled.
*/
void WiimoteManager::enableAccelerometer(bool state)
{
for (unsigned int i=0; i < m_wiimotes.size(); ++i)
{
wiiuse_motion_sensing(m_wiimotes[i]->getWiimoteHandle(), state ? 1 : 0);
}
} // enableAccelerometer
// ----------------------------------------------------------------------------
/** Thread update method - wiimotes state is updated in another thread to
* avoid latency problems */
void WiimoteManager::threadFunc() void WiimoteManager::threadFunc()
{ {
// Enable accelerometer reporting #ifdef WIIMOTE_THREADING
// TODO: this should only be done when needed (i.e when racing)
// so as to avoid wasting wiimote batteries.
// TODO: this should only be done once, but there have been reports that it didn't
// work for some people -> need to find a better fix
for (int i=0; i < MAX_WIIMOTES; ++i)
{
if(m_wiimotes[i].isConnected())
wiiuse_motion_sensing(m_wiimotes[i].getWiimoteHandle(), 1);
}
while(!m_shut) while(!m_shut)
#endif
{ {
if(wiiuse_poll(m_all_wiimote_handles, MAX_WIIMOTES)) if(wiiuse_poll(m_all_wiimote_handles, MAX_WIIMOTES))
{ {
for (int i=0; i < MAX_WIIMOTES; ++i) for (unsigned int i=0; i < m_wiimotes.size(); ++i)
{ {
if(!m_wiimotes[i].isConnected())
continue;
/*
if(WIIUSE_USING_EXP(m_wiimotes[i].getWiimoteHandle()))
{
if(WIIUSE_USING_EXP(wm))
wiiuse_set_motion_plus(m_wiimotes[i].getWiimoteHandle(), 2); // nunchuck pass-through
else
wiiuse_set_motion_plus(m_wiimotes[i].getWiimoteHandle(), 1); // standalone
}
*/
switch (m_all_wiimote_handles[i]->event) switch (m_all_wiimote_handles[i]->event)
{ {
case WIIUSE_EVENT: case WIIUSE_EVENT:
m_wiimotes[i].updateIrrEvent(); m_wiimotes[i]->update();
//printf("DEBUG: wiimote event\n"); //printf("DEBUG: wiimote event\n");
break; break;
case WIIUSE_STATUS: case WIIUSE_STATUS:
//printf("DEBUG: status event\n"); //printf("DEBUG: status event\n");
break; break;
case WIIUSE_DISCONNECT: case WIIUSE_DISCONNECT:
case WIIUSE_UNEXPECTED_DISCONNECT: case WIIUSE_UNEXPECTED_DISCONNECT:
//printf("DEBUG: wiimote disconnected\n"); //printf("DEBUG: wiimote disconnected\n");
m_wiimotes[i].setConnected(false); m_wiimotes[i]->setConnected(false);
break; break;
case WIIUSE_READ_DATA: case WIIUSE_READ_DATA:
//printf("DEBUG: WIIUSE_READ_DATA\n"); //printf("DEBUG: WIIUSE_READ_DATA\n");
break; break;
case WIIUSE_NUNCHUK_INSERTED: case WIIUSE_NUNCHUK_INSERTED:
//printf("DEBUG: Nunchuk inserted.\n"); //printf("DEBUG: Nunchuk inserted.\n");
break; break;
case WIIUSE_CLASSIC_CTRL_INSERTED: case WIIUSE_CLASSIC_CTRL_INSERTED:
//printf("DEBUG: Classic controller inserted.\n"); //printf("DEBUG: Classic controller inserted.\n");
break; break;
case WIIUSE_GUITAR_HERO_3_CTRL_INSERTED: case WIIUSE_GUITAR_HERO_3_CTRL_INSERTED:
//printf("DEBUG: Guitar Hero 3 controller inserted.\n"); //printf("DEBUG: Guitar Hero 3 controller inserted.\n");
break; break;
case WIIUSE_NUNCHUK_REMOVED: case WIIUSE_NUNCHUK_REMOVED:
case WIIUSE_CLASSIC_CTRL_REMOVED: case WIIUSE_CLASSIC_CTRL_REMOVED:
case WIIUSE_GUITAR_HERO_3_CTRL_REMOVED: case WIIUSE_GUITAR_HERO_3_CTRL_REMOVED:
@ -478,7 +310,7 @@ int WiimoteManager::askUserToConnectWiimotes()
MessageDialog::MESSAGE_DIALOG_CONFIRM, MessageDialog::MESSAGE_DIALOG_CONFIRM,
new WiimoteDialogListener(), true); new WiimoteDialogListener(), true);
return getNbWiimotes(); return getNumberOfWiimotes();
} // askUserToConnectWiimotes } // askUserToConnectWiimotes
// ============================================================================ // ============================================================================
@ -491,7 +323,7 @@ void WiimoteManager::WiimoteDialogListener::onConfirm()
wiimote_manager->launchDetection(5); wiimote_manager->launchDetection(5);
int nb_wiimotes = wiimote_manager->getNbWiimotes(); int nb_wiimotes = wiimote_manager->getNumberOfWiimotes();
if(nb_wiimotes > 0) if(nb_wiimotes > 0)
{ {
core::stringw msg = StringUtils::insertValues( core::stringw msg = StringUtils::insertValues(

View File

@ -21,15 +21,14 @@
#ifdef ENABLE_WIIUSE #ifdef ENABLE_WIIUSE
#include "input/wiimote.hpp"
#include "states_screens/dialogs/message_dialog.hpp" #include "states_screens/dialogs/message_dialog.hpp"
#include "utils/cpp2011.h" #include "utils/cpp2011.h"
#include "IEventReceiver.h" #include "IEventReceiver.h"
#include <pthread.h> #include <pthread.h>
extern const int WIIMOTE_AXES;
extern const int WIIMOTE_BUTTONS;
#define MAX_WIIMOTES 4 #define MAX_WIIMOTES 4
struct wiimote_t; struct wiimote_t;
@ -39,49 +38,6 @@ class WiimoteManager;
extern WiimoteManager* wiimote_manager; extern WiimoteManager* wiimote_manager;
/** Wiimote device class */
class Wiimote
{
private:
/** Handle to the corresponding WiiUse wiimote handle */
wiimote_t* m_wiimote_handle;
/** Index of this element the arrays of wiimotes */
int m_wiimote_id;
/** Corresponding gamepad managed by the DeviceManager */
GamePadDevice* m_gamepad_device;
/** Corresponding Irrlicht gamepad event */
irr::SEvent m_irr_event;
/** Event used for reading and writing the Irrlicht events */
pthread_mutex_t m_event_mutex;
/** Whether the wiimote received a "disconnected" event */
bool m_connected;
public:
Wiimote();
~Wiimote();
/** Resets internal state and creates the corresponding gamepad device */
void init(wiimote_t* wiimote_handle, int wiimote_id, GamepadConfig* gamepad_config);
/** To be called when the wiimote becomes unused */
void cleanup();
/** Called from the update thread: updates the Irrlicht event from the wiimote state */
void updateIrrEvent();
/** Thread-safe reading of the last updated event */
irr::SEvent getIrrEvent();
wiimote_t* getWiimoteHandle() const {return m_wiimote_handle;}
bool isConnected() const {return m_connected;}
void setConnected(bool connected) {m_connected=connected;}
};
/** Wiimote manager: handles wiimote connection, disconnection, /** Wiimote manager: handles wiimote connection, disconnection,
* gamepad configuration and input handling * gamepad configuration and input handling
@ -89,21 +45,32 @@ public:
class WiimoteManager class WiimoteManager
{ {
private: private:
Wiimote m_wiimotes[MAX_WIIMOTES]; /** List of all connected wiimotes. */
std::vector<Wiimote*> m_wiimotes;
/** WiiUse wiimote handles */ /** WiiUse wiimote handles */
wiimote_t** m_all_wiimote_handles; wiimote_t** m_all_wiimote_handles;
int m_nb_wiimotes; int m_number_wiimotes;
// While the wiimote code can technically work without threading,
// its too slow (high latency), but it is useful for debugging.
#define WIIMOTE_THREADING
#ifdef WIIMOTE_THREADING
/** Wiimote state update thread */ /** Wiimote state update thread */
pthread_t m_thread; pthread_t m_thread;
/** Shut the update thread? */ /** Shut the update thread? */
bool m_shut; bool m_shut;
#endif
/** True if wii is enabled via command line option. */ /** True if wii is enabled via command line option. */
static bool m_enabled; static bool m_enabled;
/** Wiimotes update thread */
void threadFunc();
static void* threadFuncWrapper(void* data);
void setWiimoteBindings(GamepadConfig* gamepad_config);
public: public:
WiimoteManager(); WiimoteManager();
~WiimoteManager(); ~WiimoteManager();
@ -117,15 +84,9 @@ public:
void launchDetection(int timeout); void launchDetection(int timeout);
void update(); void update();
void cleanup(); void cleanup();
int getNbWiimotes() const {return m_nb_wiimotes;}
private:
/** Wiimotes update thread */
void threadFunc();
static void* threadFuncWrapper(void* data);
public: void enableAccelerometer(bool state);
/** A simple listener to allow the user to connect wiimotes. It /** A simple listener to allow the user to connect wiimotes. It
* will display a feedback windows (# wiimotes connected or 'no wiimotes * will display a feedback windows (# wiimotes connected or 'no wiimotes
* found'). * found').
@ -140,7 +101,11 @@ public:
* \return Number of wiimotes connected. * \return Number of wiimotes connected.
*/ */
int askUserToConnectWiimotes(); int askUserToConnectWiimotes();
}; // ------------------------------------------------------------------------
/** Returns the number of wiimotes connected. */
unsigned int getNumberOfWiimotes() const {return m_wiimotes.size();}
}; // class WiimoteManager
#endif #endif