From 8c50f8ab4a2d9cd9fbae18b0e21c862402a4ee17 Mon Sep 17 00:00:00 2001 From: Steve Le Roy Harris Date: Fri, 1 Jul 2016 15:52:10 +0100 Subject: [PATCH] Initial commit --- .gitmodules | 3 + CMakeLists.txt | 30 ++++++ LICENSE | 15 +++ README.md | 12 +++ je_nourish_wiimote.cpp | 224 ++++++++++++++++++++++++++++++++++++++++ je_nourish_wiimote.json | 151 +++++++++++++++++++++++++++ vendor/wiiuse | 1 + 7 files changed, 436 insertions(+) create mode 100644 .gitmodules create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 README.md create mode 100644 je_nourish_wiimote.cpp create mode 100644 je_nourish_wiimote.json create mode 160000 vendor/wiiuse diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..af70568 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "vendor/wiiuse"] + path = vendor/wiiuse + url = https://github.com/rpavlik/wiiuse.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..bc51840 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 2.8.12) +project(WiimotePlugin) + +# in the CMake GUI or command line. +find_package(osvr REQUIRED) + +set(BUILD_WIIUSE_SHARED_LIB OFF CACHE BOOL "Should we build as a shared library (dll/so)?") +add_definitions("-DWIIUSE_STATIC") +set(BUILD_EXAMPLE OFF CACHE BOOL "Should we build the example app?") +set(BUILD_EXAMPLE_SDL OFF CACHE BOOL "Should we build the SDL-based example app?") +set(INSTALL_EXAMPLES OFF CACHE BOOL "Should we install the example apps?") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/vendor/wiiuse/cmake") + +add_subdirectory("vendor/wiiuse") + +osvr_convert_json(je_nourish_wiimote_json + je_nourish_wiimote.json + "${CMAKE_CURRENT_BINARY_DIR}/je_nourish_wiimote_json.h") + +include_directories("${CMAKE_CURRENT_BINARY_DIR}") +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/vendor/wiiuse/src") + +osvr_add_plugin(NAME je_nourish_wiimote + CPP # indicates we'd like to use the C++ wrapper + SOURCES + je_nourish_wiimote.cpp + "${CMAKE_CURRENT_BINARY_DIR}/je_nourish_wiimote_json.h") + +# If you use other libraries, find them and add a line like: +target_link_libraries(je_nourish_wiimote wiiuse) \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..dac926f --- /dev/null +++ b/LICENSE @@ -0,0 +1,15 @@ + OSVR-Wiimote + Copyright (C) 2016 Steve Le Roy Harris + + 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, see . \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..0c13749 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# OSVR Wiimote Plugin {#WiimotePluginReadme} + +An OSVR plugin providing up to four Wii Remote + Nuncuk devices via the wiiuse library. There's one orientation only tracker per wiimote or nunchuk, although yaw is only available if using the sensor bar. + +Default mappings are for one wiimote in the right hand and nunchuk in the left, but it's more fun with a nunchuk in each hand! + + git clone https://github.com/simlrh/OSVR-Wiimote + cd OSVR-Wiimote + git submodule init + git submoule update + +Then follow the [standard OSVR plugin build instructions](http://resource.osvr.com/docs/OSVR-Core/TopicWritingDevicePlugin.html). \ No newline at end of file diff --git a/je_nourish_wiimote.cpp b/je_nourish_wiimote.cpp new file mode 100644 index 0000000..3700e4c --- /dev/null +++ b/je_nourish_wiimote.cpp @@ -0,0 +1,224 @@ +// Internal Includes +#include +#include +#include +#include + +// Generated JSON header file +#include "je_nourish_wiimote_json.h" + +// Library/third-party includes +#include "wiiuse.h" + +// Standard includes +#include +#define _USE_MATH_DEFINES +#include + +#define MAX_WIIMOTES 4 +#define TRACKERS_PER_WIIMOTE 2 +#define BUTTONS_PER_WIIMOTE 13 +#define ANALOG_PER_WIIMOTE 5 + +// Anonymous namespace to avoid symbol collision +namespace { + + class WiimoteDevice { + public: + WiimoteDevice(OSVR_PluginRegContext ctx) { + int found, connected; + + m_wiimotes = wiiuse_init(MAX_WIIMOTES); + found = wiiuse_find(m_wiimotes, MAX_WIIMOTES, 5); + connected = wiiuse_connect(m_wiimotes, MAX_WIIMOTES); + + wiiuse_set_leds(m_wiimotes[0], WIIMOTE_LED_1); + wiiuse_set_leds(m_wiimotes[1], WIIMOTE_LED_2); + wiiuse_set_leds(m_wiimotes[2], WIIMOTE_LED_3); + wiiuse_set_leds(m_wiimotes[3], WIIMOTE_LED_4); + + wiiuse_motion_sensing(m_wiimotes[0], 1); + wiiuse_motion_sensing(m_wiimotes[1], 1); + wiiuse_motion_sensing(m_wiimotes[2], 1); + wiiuse_motion_sensing(m_wiimotes[3], 1); + + /// Create the initialization options + OSVR_DeviceInitOptions opts = osvrDeviceCreateInitOptions(ctx); + + osvrDeviceTrackerConfigure(opts, &m_tracker); + osvrDeviceAnalogConfigure(opts, &m_analog, 20); + osvrDeviceButtonConfigure(opts, &m_button, 52); + + /// Create the device token with the options + m_dev.initAsync(ctx, "WiimoteDevice", opts); + + /// Send JSON descriptor + m_dev.sendJsonDescriptor(je_nourish_wiimote_json); + + /// Register update callback + m_dev.registerUpdateCallback(this); + } + + ~WiimoteDevice() { + wiiuse_cleanup(m_wiimotes, MAX_WIIMOTES); + } + + OSVR_ReturnCode update() { + struct wiimote_t* wm; + OSVR_Vec3 wm_rpy; + OSVR_Quaternion wm_quaternion; + OSVR_Vec3 nc_rpy; + OSVR_Quaternion nc_quaternion; + + osvrVec3Zero(&wm_rpy); + osvrQuatSetIdentity(&wm_quaternion); + osvrVec3Zero(&nc_rpy); + osvrQuatSetIdentity(&nc_quaternion); + + if (wiimote_connected()) { + wiiuse_poll(m_wiimotes, MAX_WIIMOTES); + + OSVR_ButtonState buttons[BUTTONS_PER_WIIMOTE * MAX_WIIMOTES]; + OSVR_AnalogState analog[ANALOG_PER_WIIMOTE * MAX_WIIMOTES]; + + for (int i = 0; i < MAX_WIIMOTES; i++) { + wm = m_wiimotes[i]; + + if (wm->event == WIIUSE_EVENT) { + buttons[BUTTONS_PER_WIIMOTE*i + 0] = IS_PRESSED(wm, WIIMOTE_BUTTON_A); + buttons[BUTTONS_PER_WIIMOTE*i + 1] = IS_PRESSED(wm, WIIMOTE_BUTTON_B); + buttons[BUTTONS_PER_WIIMOTE*i + 2] = IS_PRESSED(wm, WIIMOTE_BUTTON_UP); + buttons[BUTTONS_PER_WIIMOTE*i + 3] = IS_PRESSED(wm, WIIMOTE_BUTTON_DOWN); + buttons[BUTTONS_PER_WIIMOTE*i + 4] = IS_PRESSED(wm, WIIMOTE_BUTTON_LEFT); + buttons[BUTTONS_PER_WIIMOTE*i + 5] = IS_PRESSED(wm, WIIMOTE_BUTTON_RIGHT); + buttons[BUTTONS_PER_WIIMOTE*i + 6] = IS_PRESSED(wm, WIIMOTE_BUTTON_ONE); + buttons[BUTTONS_PER_WIIMOTE*i + 7] = IS_PRESSED(wm, WIIMOTE_BUTTON_TWO); + buttons[BUTTONS_PER_WIIMOTE*i + 8] = IS_PRESSED(wm, WIIMOTE_BUTTON_MINUS); + buttons[BUTTONS_PER_WIIMOTE*i + 9] = IS_PRESSED(wm, WIIMOTE_BUTTON_PLUS); + buttons[BUTTONS_PER_WIIMOTE*i + 10] = IS_PRESSED(wm, WIIMOTE_BUTTON_HOME); + + if (WIIUSE_USING_ACC(wm)) { + + osvrVec3SetX(&wm_rpy, -wm->orient.roll * M_PI / 180); + osvrVec3SetY(&wm_rpy, -wm->orient.pitch * M_PI / 180); + osvrVec3SetZ(&wm_rpy, -wm->orient.yaw * M_PI / 180); + + WiimoteDevice::quaternionFromRPY(&wm_rpy, &wm_quaternion); + + osvrDeviceTrackerSendOrientation(m_dev, m_tracker, &wm_quaternion, (TRACKERS_PER_WIIMOTE * i)); + } + + if (WIIUSE_USING_IR(wm)) { + analog[ANALOG_PER_WIIMOTE*i + 0] = wm->ir.x; + analog[ANALOG_PER_WIIMOTE*i + 1] = wm->ir.y; + analog[ANALOG_PER_WIIMOTE*i + 2] = wm->ir.z; + } + else { + analog[ANALOG_PER_WIIMOTE*i + 0] = 0; + analog[ANALOG_PER_WIIMOTE*i + 1] = 0; + analog[ANALOG_PER_WIIMOTE*i + 2] = 0; + } + + if (wm->exp.type == EXP_NUNCHUK || wm->exp.type == EXP_MOTION_PLUS_NUNCHUK) { + struct nunchuk_t* nc = (nunchuk_t*)&wm->exp.nunchuk; + + buttons[BUTTONS_PER_WIIMOTE*i + 11] = IS_PRESSED(wm, NUNCHUK_BUTTON_C); + buttons[BUTTONS_PER_WIIMOTE*i + 12] = IS_PRESSED(wm, NUNCHUK_BUTTON_Z); + + analog[ANALOG_PER_WIIMOTE*i + 3] = nc->js.x; + analog[ANALOG_PER_WIIMOTE*i + 4] = nc->js.y; + + osvrVec3SetX(&nc_rpy, -nc->orient.roll * M_PI / 180); + osvrVec3SetY(&nc_rpy, -nc->orient.pitch * M_PI / 180); + osvrVec3SetZ(&nc_rpy, -nc->orient.yaw * M_PI / 180); + + WiimoteDevice::quaternionFromRPY(&nc_rpy, &nc_quaternion); + + osvrDeviceTrackerSendOrientation(m_dev, m_tracker, &nc_quaternion, (TRACKERS_PER_WIIMOTE * i) + 1); + } + else { + buttons[BUTTONS_PER_WIIMOTE*i + 11] = false; + buttons[BUTTONS_PER_WIIMOTE*i + 12] = false; + analog[ANALOG_PER_WIIMOTE*i + 3] = 0; + analog[ANALOG_PER_WIIMOTE*i + 4] = 0; + } + } + else { + buttons[BUTTONS_PER_WIIMOTE*i + 0] = false; + buttons[BUTTONS_PER_WIIMOTE*i + 1] = false; + buttons[BUTTONS_PER_WIIMOTE*i + 2] = false; + buttons[BUTTONS_PER_WIIMOTE*i + 3] = false; + buttons[BUTTONS_PER_WIIMOTE*i + 4] = false; + buttons[BUTTONS_PER_WIIMOTE*i + 5] = false; + buttons[BUTTONS_PER_WIIMOTE*i + 6] = false; + buttons[BUTTONS_PER_WIIMOTE*i + 7] = false; + buttons[BUTTONS_PER_WIIMOTE*i + 8] = false; + buttons[BUTTONS_PER_WIIMOTE*i + 9] = false; + buttons[BUTTONS_PER_WIIMOTE*i + 10] = false; + buttons[BUTTONS_PER_WIIMOTE*i + 11] = false; + buttons[BUTTONS_PER_WIIMOTE*i + 12] = false; + } + } + + osvrDeviceAnalogSetValues(m_dev, m_analog, analog, 20); + osvrDeviceButtonSetValues(m_dev, m_button, buttons, 52); + } + + return OSVR_RETURN_SUCCESS; + } + + private: + bool wiimote_connected() { + for (int i = 0; i < MAX_WIIMOTES; i++) { + if (m_wiimotes[i] && WIIMOTE_IS_CONNECTED(m_wiimotes[i])) { + return true; + } + } + return false; + } + static void quaternionFromRPY(OSVR_Vec3* rpy, OSVR_Quaternion* quaternion) { + double r = osvrVec3GetX(rpy); + double p = osvrVec3GetY(rpy); + double y = osvrVec3GetZ(rpy); + + osvrQuatSetZ(quaternion, sin(r / 2) * cos(p / 2) * cos(y / 2) - cos(r / 2) * sin(p / 2) * sin(y / 2)); + osvrQuatSetX(quaternion, cos(r / 2) * sin(p / 2) * cos(y / 2) + sin(r / 2) * cos(p / 2) * sin(y / 2)); + osvrQuatSetY(quaternion, cos(r / 2) * cos(p / 2) * sin(y / 2) - sin(r / 2) * sin(p / 2) * cos(y / 2)); + osvrQuatSetW(quaternion, cos(r / 2) * cos(p / 2) * cos(y / 2) + sin(r / 2) * sin(p / 2) * sin(y / 2)); + } + + wiimote** m_wiimotes; + osvr::pluginkit::DeviceToken m_dev; + OSVR_TrackerDeviceInterface m_tracker; + OSVR_AnalogDeviceInterface m_analog; + OSVR_ButtonDeviceInterface m_button; + }; + + class HardwareDetection { + public: + HardwareDetection() : m_found(false) {} + OSVR_ReturnCode operator()(OSVR_PluginRegContext ctx) { + + if (!m_found) { + m_found = true; + + osvr::pluginkit::registerObjectForDeletion( + ctx, new WiimoteDevice(ctx)); + } + return OSVR_RETURN_SUCCESS; + } + + private: + bool m_found; + + }; +} // namespace + +OSVR_PLUGIN(je_nourish_wiimote) { + osvr::pluginkit::PluginContext context(ctx); + + /// Register a detection callback function object. + context.registerHardwareDetectCallback(new HardwareDetection()); + + return OSVR_RETURN_SUCCESS; +} diff --git a/je_nourish_wiimote.json b/je_nourish_wiimote.json new file mode 100644 index 0000000..2214ecb --- /dev/null +++ b/je_nourish_wiimote.json @@ -0,0 +1,151 @@ +{ + "deviceVendor": "Nintento", + "deviceName": "Wiimote", + "author": "Steve Le Roy Harris ", + "version": 1, + "lastModified": "2016-07-01T21:13:07.585Z", + "interfaces": { + "tracker": { + "count": 8, + "orientation": true, + "position": false + }, + "analog": { + "count": 20 + }, + "button": { + "count": 52 + } + }, + "semantic": { + "wiimote1": { + "$target": "tracker/0", + "a": "button/0", + "b": "button/1", + "up": "button/2", + "down": "button/3", + "left": "button/4", + "right": "button/5", + "one": "button/6", + "two": "button/7", + "minus": "button/8", + "plus": "button/9", + "home": "button/10", + "ir": { + "x": "analog/0", + "y": "analog/1", + "z": "analog/2" + }, + "nunchuk": { + "$target": "tracker/1", + "c": "button/11", + "z": "button/12", + "joystick": { + "x": "analog/3", + "y": "analog/4" + } + } + }, + "wiimote2": { + "$target": "tracker/2", + "a": "button/13", + "b": "button/14", + "up": "button/15", + "down": "button/16", + "left": "button/17", + "right": "button/18", + "one": "button/19", + "two": "button/20", + "minus": "button/21", + "plus": "button/22", + "home": "button/23", + "ir": { + "x": "analog/5", + "y": "analog/6", + "z": "analog/7" + }, + "nunchuk": { + "$target": "tracker/3", + "c": "button/24", + "z": "button/25", + "joystick": { + "x": "analog/8", + "y": "analog/9" + } + } + }, + "wiimote3": { + "$target": "tracker/4", + "a": "button/26", + "b": "button/27", + "up": "button/28", + "down": "button/29", + "left": "button/30", + "right": "button/31", + "one": "button/32", + "two": "button/33", + "minus": "button/34", + "plus": "button/35", + "home": "button/36", + "ir": { + "x": "analog/10", + "y": "analog/11", + "z": "analog/12" + }, + "nunchuk": { + "$target": "tracker/5", + "c": "button/37", + "z": "button/38", + "joystick": { + "x": "analog/13", + "y": "analog/14" + } + } + }, + "wiimote4": { + "$target": "tracker/6", + "a": "button/39", + "b": "button/40", + "up": "button/41", + "down": "button/42", + "left": "button/43", + "right": "button/44", + "one": "button/45", + "two": "button/46", + "minus": "button/47", + "plus": "button/48", + "home": "button/49", + "ir": { + "x": "analog/15", + "y": "analog/16", + "z": "analog/17" + }, + "nunchuk": { + "$target": "tracker/7", + "c": "button/50", + "z": "button/51", + "joystick": { + "x": "analog/18", + "y": "analog/19" + } + } + } + }, + "automaticAliases": { + "/me/hands/right": "semantic/wiimote1", + "/controller/right/1": "semantic/wiimote1/a", + "/controller/right/2": "semantic/wiimote1/left", + "/controller/right/3": "semantic/wiimote1/right", + "/controller/right/4": "semantic/wiimote1/up", + "/controller/right/bumper": "semantic/wiimote1/down", + "/controller/right/joystick/button": "semantic/wiimote1/home", + "/controller/right/middle": "semantic/wiimote1/one", + "/controller/right/trigger": "semantic/wiimote1/b", + + "/me/hands/left": "semantic/wiimote1/nunchuk", + "/controller/left/1": "semantic/wiimote1/nunchuk/c", + "/controller/left/joystick/x": "semantic/wiimote1/nunchuk/joystick/x", + "/controller/left/joystick/y": "semantic/wiimote1/nunchuk/joystick/y", + "/controller/left/trigger": "semantic/wiimote1/z" + } +} diff --git a/vendor/wiiuse b/vendor/wiiuse new file mode 160000 index 0000000..ecb5fa3 --- /dev/null +++ b/vendor/wiiuse @@ -0,0 +1 @@ +Subproject commit ecb5fa30bdb6cb58f5d04b4aeedd5f433e36917a