diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 02b124e79..ad74adff8 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -266,7 +266,7 @@ if(BUILD_OPENMW_VR) FetchContent_Declare( OpenXR GIT_REPOSITORY https://github.com/KhronosGroup/OpenXR-SDK.git - GIT_TAG release-1.0.9 + GIT_TAG release-1.0.12 ) FetchContent_MakeAvailable(OpenXR) diff --git a/apps/openmw/mwvr/openxractionset.cpp b/apps/openmw/mwvr/openxractionset.cpp index 4fb853c45..7434b70c8 100644 --- a/apps/openmw/mwvr/openxractionset.cpp +++ b/apps/openmw/mwvr/openxractionset.cpp @@ -25,24 +25,6 @@ namespace MWVR // Currently the set of action paths was determined using the oculus touch (i know nothing about the vive and the index). // The set of action paths may therefore need expansion. E.g. /click vs /value may vary with controllers. - // To fit more actions onto controllers i created a system of short and long press actions. Allowing one action to activate - // on a short press, and another on long. Here, what actions are short press and what actions are long press is simply - // hardcoded at init, rather than interpreted from bindings. That's bad, and should be fixed, but that's hard to do - // while staying true to openxr's binding system, so if the system i wrote for the oculus touch isn't a good fit for - // the vive/index, we might want to rewrite this to handle bindings ourselves. - generateControllerActionPaths(ActionPath::Select, "/input/select/click"); - generateControllerActionPaths(ActionPath::Squeeze, "/input/squeeze/value"); - generateControllerActionPaths(ActionPath::Pose, "/input/aim/pose"); - generateControllerActionPaths(ActionPath::Haptic, "/output/haptic"); - generateControllerActionPaths(ActionPath::Menu, "/input/menu/click"); - generateControllerActionPaths(ActionPath::ThumbstickX, "/input/thumbstick/x"); - generateControllerActionPaths(ActionPath::ThumbstickY, "/input/thumbstick/y"); - generateControllerActionPaths(ActionPath::ThumbstickClick, "/input/thumbstick/click"); - generateControllerActionPaths(ActionPath::X, "/input/x/click"); - generateControllerActionPaths(ActionPath::Y, "/input/y/click"); - generateControllerActionPaths(ActionPath::A, "/input/a/click"); - generateControllerActionPaths(ActionPath::B, "/input/b/click"); - generateControllerActionPaths(ActionPath::Trigger, "/input/trigger/value"); /* // Applicable actions not (yet) included @@ -65,6 +47,12 @@ namespace MWVR A_Screenshot, // Generate a VR screenshot? A_Console, // Currently awkward due to a lack of virtual keyboard, but should be included when that's in place */ + + // To fit more actions onto controllers i created a system of short and long press actions. Allowing one action to activate + // on a short press, and another on long. Here, what actions are short press and what actions are long press is simply + // hardcoded at init, rather than interpreted from bindings. That's bad, and should be fixed, but that's hard to do + // while staying true to openxr's binding system, so if the system i wrote for the oculus touch isn't a good fit for + // the vive/index, we might want to rewrite this to handle bindings ourselves. createMWAction(MWInput::A_GameMenu, "game_menu", "Game Menu"); createMWAction(A_Recenter, "reposition_menu", "Reposition Menu"); createMWAction(MWInput::A_Inventory, "inventory", "Inventory"); @@ -147,10 +135,10 @@ namespace MWVR { std::vector suggestedBindings = { - {*mTrackerMap[TrackedLimb::LEFT_HAND], getXrPath(ActionPath::Pose, Side::LEFT_SIDE)}, - {*mTrackerMap[TrackedLimb::RIGHT_HAND], getXrPath(ActionPath::Pose, Side::RIGHT_SIDE)}, - {*mHapticsMap[TrackedLimb::LEFT_HAND], getXrPath(ActionPath::Haptic, Side::LEFT_SIDE)}, - {*mHapticsMap[TrackedLimb::RIGHT_HAND], getXrPath(ActionPath::Haptic, Side::RIGHT_SIDE)}, + {*mTrackerMap[TrackedLimb::LEFT_HAND], getXrPath("/user/hand/left/input/aim/pose")}, + {*mTrackerMap[TrackedLimb::RIGHT_HAND], getXrPath("/user/hand/right/input/aim/pose")}, + {*mHapticsMap[TrackedLimb::LEFT_HAND], getXrPath("/user/hand/left/output/haptic")}, + {*mHapticsMap[TrackedLimb::RIGHT_HAND], getXrPath("/user/hand/right/output/haptic")}, }; for (auto& mwSuggestedBinding : mwSuggestedBindings) @@ -161,29 +149,12 @@ namespace MWVR Log(Debug::Error) << "OpenXRActionSet: Unknown action " << mwSuggestedBinding.action; continue; } - suggestedBindings.push_back({ *xrAction->second, getXrPath(mwSuggestedBinding.path, mwSuggestedBinding.side) }); + suggestedBindings.push_back({ *xrAction->second, getXrPath(mwSuggestedBinding.path) }); } xrSuggestedBindings.insert(xrSuggestedBindings.end(), suggestedBindings.begin(), suggestedBindings.end()); } - void - OpenXRActionSet::generateControllerActionPaths( - ActionPath actionPath, - const std::string& controllerAction) - { - auto* xr = Environment::get().getManager(); - ControllerActionPaths actionPaths; - - std::string left = std::string("/user/hand/left") + controllerAction; - std::string right = std::string("/user/hand/right") + controllerAction; - - CHECK_XRCMD(xrStringToPath(xr->impl().xrInstance(), left.c_str(), &actionPaths[(int)Side::LEFT_SIDE])); - CHECK_XRCMD(xrStringToPath(xr->impl().xrInstance(), right.c_str(), &actionPaths[(int)Side::RIGHT_SIDE])); - - mPathMap[actionPath] = actionPaths; - } - std::unique_ptr OpenXRActionSet::createXRAction( @@ -219,7 +190,7 @@ namespace MWVR action.second->updateAndQueue(mActionQueue); } - XrPath OpenXRActionSet::generateXrPath(const std::string& path) + XrPath OpenXRActionSet::getXrPath(const std::string& path) { auto* xr = Environment::get().getManager(); XrPath xrpath = 0; @@ -265,13 +236,4 @@ namespace MWVR it->second->apply(intensity); } - XrPath OpenXRActionSet::getXrPath(ActionPath actionPath, Side side) - { - auto it = mPathMap.find(actionPath); - if (it == mPathMap.end()) - { - Log(Debug::Error) << "OpenXRActionSet: No such path: " << (int)actionPath; - } - return it->second[(int)side]; - } } diff --git a/apps/openmw/mwvr/openxractionset.hpp b/apps/openmw/mwvr/openxractionset.hpp index bac136e9d..c1913daab 100644 --- a/apps/openmw/mwvr/openxractionset.hpp +++ b/apps/openmw/mwvr/openxractionset.hpp @@ -13,7 +13,6 @@ namespace MWVR { public: using Actions = MWInput::Actions; - using ControllerActionPaths = std::array; OpenXRActionSet(const std::string& actionSetName); @@ -38,15 +37,12 @@ namespace MWVR void createPoseAction(TrackedLimb limb, const std::string& actionName, const std::string& localName); void createHapticsAction(TrackedLimb limb, const std::string& actionName, const std::string& localName); std::unique_ptr createXRAction(XrActionType actionType, const std::string& actionName, const std::string& localName); - XrPath generateXrPath(const std::string& path); - void generateControllerActionPaths(ActionPath actionPath, const std::string& controllerAction); + XrPath getXrPath(const std::string& path); XrActionSet createActionSet(const std::string& name); - XrPath getXrPath(ActionPath actionPath, Side side); XrActionSet mActionSet{ nullptr }; std::string mLocalizedName{}; std::string mInternalName{}; - std::map mPathMap; std::map> mActionMap; std::map> mTrackerMap; std::map> mHapticsMap; diff --git a/apps/openmw/mwvr/openxrinput.cpp b/apps/openmw/mwvr/openxrinput.cpp index e725c8f36..978c2cbd3 100644 --- a/apps/openmw/mwvr/openxrinput.cpp +++ b/apps/openmw/mwvr/openxrinput.cpp @@ -40,7 +40,7 @@ namespace MWVR // Suggest bindings before attaching for (auto& profile : mSuggestedBindings) { - XrPath profilePath; + XrPath profilePath = 0; CHECK_XRCMD( xrStringToPath(xr->impl().xrInstance(), profile.first.c_str(), &profilePath)); XrInteractionProfileSuggestedBinding xrProfileSuggestedBindings{ XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING }; diff --git a/apps/openmw/mwvr/openxrmanagerimpl.cpp b/apps/openmw/mwvr/openxrmanagerimpl.cpp index 2220c173a..468790d5d 100644 --- a/apps/openmw/mwvr/openxrmanagerimpl.cpp +++ b/apps/openmw/mwvr/openxrmanagerimpl.cpp @@ -16,10 +16,10 @@ #include "../mwworld/player.hpp" #include "../mwworld/esmstore.hpp" -// The OpenXR SDK assumes we've included Windows.h +// The OpenXR SDK's platform headers assume we've included these windows headers #include +#include -#include #include #include #include @@ -48,18 +48,17 @@ MAKE_TO_STRING_FUNC(XrResult); MAKE_TO_STRING_FUNC(XrFormFactor); MAKE_TO_STRING_FUNC(XrStructureType); -#if !XR_KHR_composition_layer_depth || !XR_KHR_opengl_enable -#error "OpenXR extensions missing. Please upgrade your copy of the OpenXR SDK" -#endif - namespace MWVR { OpenXRManagerImpl::OpenXRManagerImpl() { - std::vector extensions = { - XR_KHR_OPENGL_ENABLE_EXTENSION_NAME, - XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME, - }; + setupExtensionsAndLayers(); + + std::vector extensions; + for (auto& extension : mEnabledExtensions) + extensions.push_back(extension.c_str()); + + logLayersAndExtensions(); { // Create Instance XrInstanceCreateInfo createInfo{ XR_TYPE_INSTANCE_CREATE_INFO }; @@ -68,33 +67,7 @@ namespace MWVR createInfo.enabledExtensionNames = extensions.data(); strcpy(createInfo.applicationInfo.applicationName, "openmw_vr"); createInfo.applicationInfo.apiVersion = XR_CURRENT_API_VERSION; - // Iteratively strip extensions until instance creation succeeds. - XrResult result = xrCreateInstance(&createInfo, &mInstance); - while (result == XR_ERROR_EXTENSION_NOT_PRESENT) - { - createInfo.enabledExtensionCount--; - result = xrCreateInstance(&createInfo, &mInstance); - } - - mEnabledExtensions.insert(extensions.begin(), extensions.begin() + createInfo.enabledExtensionCount); - - if (!xrExtensionIsEnabled(XR_KHR_OPENGL_ENABLE_EXTENSION_NAME)) - throw std::runtime_error(std::string("Required OpenXR extension ") + XR_KHR_OPENGL_ENABLE_EXTENSION_NAME + " not supported"); - - Log(Debug::Verbose) << "OpenXR Extension status:"; - for (auto* ext : extensions) - { - if (!xrExtensionIsEnabled(ext)) - { - Log(Debug::Verbose) << " " << ext << ": disabled (not supported)"; - } - else - { - Log(Debug::Verbose) << " " << ext << ": enabled"; - } - } - - + CHECK_XRCMD(xrCreateInstance(&createInfo, &mInstance)); assert(mInstance); } @@ -142,32 +115,24 @@ namespace MWVR auto DC = wglGetCurrentDC(); auto GLRC = wglGetCurrentContext(); auto XRGLRC = wglCreateContext(DC); - auto USERGLRC = wglCreateContext(DC); wglShareLists(GLRC, XRGLRC); - wglShareLists(GLRC, USERGLRC); - mGraphicsBindingXr.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR; - mGraphicsBindingXr.next = nullptr; - mGraphicsBindingXr.hDC = DC; - mGraphicsBindingXr.hGLRC = XRGLRC; - mGraphicsBindingUser.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR; - mGraphicsBindingUser.next = nullptr; - mGraphicsBindingUser.hDC = DC; - mGraphicsBindingUser.hGLRC = USERGLRC; + XrGraphicsBindingOpenGLWin32KHR graphicsBindings; + graphicsBindings.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR; + graphicsBindings.next = nullptr; + graphicsBindings.hDC = DC; + graphicsBindings.hGLRC = XRGLRC; - if (!mGraphicsBindingXr.hDC) + if (!graphicsBindings.hDC) Log(Debug::Warning) << "Missing DC"; - if (!mGraphicsBindingXr.hGLRC) - Log(Debug::Warning) << "Missing GLRC"; XrSessionCreateInfo createInfo{ XR_TYPE_SESSION_CREATE_INFO }; - createInfo.next = &mGraphicsBindingXr; + createInfo.next = &graphicsBindings; createInfo.systemId = mSystemId; CHECK_XRCMD(xrCreateSession(mInstance, &createInfo, &mSession)); assert(mSession); } - LogLayersAndExtensions(); LogInstanceInfo(); LogReferenceSpaces(); LogSwapchainFormats(); @@ -254,9 +219,67 @@ namespace MWVR } +#if !XR_KHR_composition_layer_depth \ + || !XR_KHR_opengl_enable \ + || !XR_EXT_hp_mixed_reality_controller + +#error "OpenXR extensions missing. Please upgrade your copy of the OpenXR SDK to 1.0.12 minimum" +#endif + + std::vector OpenXRManagerImpl::enumerateExtensions(const char* layerName) + { + uint32_t extensionCount = 0; + std::vector availableExtensions; + xrEnumerateInstanceExtensionProperties(nullptr, 0, &extensionCount, nullptr); + availableExtensions.resize(extensionCount, XrExtensionProperties{ XR_TYPE_EXTENSION_PROPERTIES }); + xrEnumerateInstanceExtensionProperties(nullptr, availableExtensions.size(), &extensionCount, availableExtensions.data()); + std::vector extensionNames; + for (auto& extension : availableExtensions) + extensionNames.push_back(extension.extensionName); + return extensionNames; + } + + void OpenXRManagerImpl::setupExtensionsAndLayers() + { + std::vector requiredExtensions = { + XR_KHR_OPENGL_ENABLE_EXTENSION_NAME, + }; + + std::vector optionalExtensions = { + XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME, + XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME + }; + + for (auto& extension : enumerateExtensions()) + mAvailableExtensions.insert(extension); + + for (auto requiredExtension : requiredExtensions) + enableExtension(requiredExtension, false); + + for (auto optionalExtension : optionalExtensions) + enableExtension(optionalExtension, true); + + } + + void OpenXRManagerImpl::enableExtension(const std::string& extension, bool optional) + { + if (mAvailableExtensions.count(extension) > 0) + { + Log(Debug::Verbose) << " " << extension << ": enabled"; + mEnabledExtensions.insert(extension); + } + else + { + Log(Debug::Verbose) << " " << extension << ": disabled (not supported)"; + if (!optional) + { + throw std::runtime_error(std::string("Required OpenXR extension ") + extension + " not supported by the runtime"); + } + } + } void - OpenXRManagerImpl::LogLayersAndExtensions() { + OpenXRManagerImpl::logLayersAndExtensions() { // Write out extension properties for a given layer. const auto logExtensions = [](const char* layerName, int indent = 0) { uint32_t instanceExtensionCount; @@ -283,9 +306,6 @@ namespace MWVR Log(Debug::Verbose) << ss.str(); }; - // Log non-layer extensions (layerName==nullptr). - logExtensions(nullptr); - // Log layers and any of their extensions. { uint32_t layerCount; @@ -382,15 +402,8 @@ namespace MWVR void OpenXRManagerImpl::beginFrame() { - auto DC = wglGetCurrentDC(); - auto GLRC = wglGetCurrentContext(); - wglMakeCurrent(mGraphicsBindingUser.hDC, mGraphicsBindingUser.hGLRC); - clearGlErrors(); XrFrameBeginInfo frameBeginInfo{ XR_TYPE_FRAME_BEGIN_INFO }; - CHECK_XRCMD(xrBeginFrame(mSession, &frameBeginInfo)); - - wglMakeCurrent(DC, GLRC); } XrCompositionLayerProjectionView toXR(MWVR::CompositionLayerProjectionView layer) @@ -408,11 +421,6 @@ namespace MWVR void OpenXRManagerImpl::endFrame(FrameInfo frameInfo, int layerCount, const std::array& layerStack) { - auto DC = wglGetCurrentDC(); - auto GLRC = wglGetCurrentContext(); - wglMakeCurrent(mGraphicsBindingUser.hDC, mGraphicsBindingUser.hGLRC); - clearGlErrors(); - std::array compositionLayerProjectionViews{}; compositionLayerProjectionViews[(int)Side::LEFT_SIDE] = toXR(layerStack[(int)Side::LEFT_SIDE]); compositionLayerProjectionViews[(int)Side::RIGHT_SIDE] = toXR(layerStack[(int)Side::RIGHT_SIDE]); @@ -449,8 +457,6 @@ namespace MWVR frameEndInfo.layers = &xrLayerStack; } CHECK_XRCMD(xrEndFrame(mSession, &frameEndInfo)); - - wglMakeCurrent(DC, GLRC); } std::array diff --git a/apps/openmw/mwvr/openxrmanagerimpl.hpp b/apps/openmw/mwvr/openxrmanagerimpl.hpp index d04911dc8..597dd50a0 100644 --- a/apps/openmw/mwvr/openxrmanagerimpl.hpp +++ b/apps/openmw/mwvr/openxrmanagerimpl.hpp @@ -7,13 +7,7 @@ #include #include -// The OpenXR SDK assumes we've included Windows.h -#include - #include -#include -#include -#include #include #include @@ -77,7 +71,10 @@ namespace MWVR void xrResourceReleased(); protected: - void LogLayersAndExtensions(); + std::vector enumerateExtensions(const char* layerName = nullptr); + void setupExtensionsAndLayers(); + void enableExtension(const std::string& extension, bool optional); + void logLayersAndExtensions(); void LogInstanceInfo(); void LogReferenceSpaces(); void LogSwapchainFormats(); @@ -100,8 +97,6 @@ namespace MWVR XrViewConfigurationType mViewConfigType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; XrEnvironmentBlendMode mEnvironmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE; XrSystemId mSystemId = XR_NULL_SYSTEM_ID; - XrGraphicsBindingOpenGLWin32KHR mGraphicsBindingXr{ XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR }; - XrGraphicsBindingOpenGLWin32KHR mGraphicsBindingUser{ XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR }; XrSystemProperties mSystemProperties{ XR_TYPE_SYSTEM_PROPERTIES }; std::array mConfigViews{ { {XR_TYPE_VIEW_CONFIGURATION_VIEW}, {XR_TYPE_VIEW_CONFIGURATION_VIEW} } }; XrSpace mReferenceSpaceView = XR_NULL_HANDLE; @@ -113,6 +108,7 @@ namespace MWVR uint32_t mAcquiredResources = 0; std::mutex mFrameStateMutex{}; std::mutex mEventMutex{}; + std::set mAvailableExtensions; std::set mEnabledExtensions; std::queue mEventQueue; diff --git a/apps/openmw/mwvr/openxrswapchain.cpp b/apps/openmw/mwvr/openxrswapchain.cpp index 4b2c509e7..101c0b5d4 100644 --- a/apps/openmw/mwvr/openxrswapchain.cpp +++ b/apps/openmw/mwvr/openxrswapchain.cpp @@ -6,13 +6,6 @@ #include -#include - -#include -#include -#include -#include - namespace MWVR { OpenXRSwapchain::OpenXRSwapchain(osg::ref_ptr state, SwapchainConfig config) : mPrivate(new OpenXRSwapchainImpl(state, config)) diff --git a/apps/openmw/mwvr/openxrswapchainimpl.cpp b/apps/openmw/mwvr/openxrswapchainimpl.cpp index 900cfd94e..1b2c3ce5e 100644 --- a/apps/openmw/mwvr/openxrswapchainimpl.cpp +++ b/apps/openmw/mwvr/openxrswapchainimpl.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include diff --git a/apps/openmw/mwvr/openxrswapchainimpl.hpp b/apps/openmw/mwvr/openxrswapchainimpl.hpp index b56f4202a..45a6b9d55 100644 --- a/apps/openmw/mwvr/openxrswapchainimpl.hpp +++ b/apps/openmw/mwvr/openxrswapchainimpl.hpp @@ -5,6 +5,7 @@ #include "openxrmanagerimpl.hpp" struct XrSwapchainSubImage; +struct XrSwapchainImageOpenGLKHR; namespace MWVR { diff --git a/apps/openmw/mwvr/vrinput.hpp b/apps/openmw/mwvr/vrinput.hpp index da6faf1e5..44bc87c84 100644 --- a/apps/openmw/mwvr/vrinput.hpp +++ b/apps/openmw/mwvr/vrinput.hpp @@ -8,8 +8,6 @@ namespace MWVR { - - /// Extension of MWInput's set of actions. enum VrActions { @@ -27,34 +25,11 @@ namespace MWVR A_VrLast }; - /// \brief Enum representation of action paths in openxr. - /// - /// OpenXR allows a lot of generics, consequentially this will most likely be changed/expanded - /// in the future as we need it. This set was added based on what the Oculus needed. - enum class ActionPath - { - Pose = 0, - Haptic, - Menu, - ThumbstickX, - ThumbstickY, - ThumbstickClick, - Select, - Squeeze, - Trigger, - X, - Y, - A, - B, - Last - }; - /// \brief Suggest a binding by binding an action to a path on a given hand (left or right). struct SuggestedBinding { int action; - ActionPath path; - Side side; + std::string path; }; using SuggestedBindings = std::vector; diff --git a/apps/openmw/mwvr/vrinputmanager.cpp b/apps/openmw/mwvr/vrinputmanager.cpp index 0e97e0b55..234bb44d7 100644 --- a/apps/openmw/mwvr/vrinputmanager.cpp +++ b/apps/openmw/mwvr/vrinputmanager.cpp @@ -167,6 +167,261 @@ namespace MWVR activeActionSet().applyHaptics(TrackedLimb::RIGHT_HAND, intensity); } + void VRInputManager::suggestBindingsSimple() + { + std::string simpleProfilePath = "/interaction_profiles/khr/simple_controller"; + // Set up default bindings for the khronos simple controller. + // Note: The simple controller is the equivalent to a universal "default". + // It has highly reduced functionality. Only poses and two click actions + // are available for each hand, reducing the possible functionality of the profile + // to that of a wonky preview. + // The available click actions are 'select' and 'menu', and i cannot control what + // real buttons this is mapped to. On the Oculus Touch they are X, Y, A, and B. + + // In-game character controls + SuggestedBindings simpleGameplayBindings{ + {MWInput::A_Use, "/user/hand/left/input/select/click"}, // Touch: X + {MWInput::A_GameMenu, "/user/hand/left/input/menu/click"}, // Touch: Y + {A_Recenter, "/user/hand/left/input/menu/click"}, // Touch: Y + {A_ActivateTouch, "/user/hand/right/input/select/click"}, // Touch: A + {MWInput::A_Inventory, "/user/hand/right/input/menu/click"}, // Touch: B + }; + + // GUI controls + SuggestedBindings simpleGUIBindings{ + {MWInput::A_Use, "/user/hand/left/input/select/click"}, // Touch: X + {MWInput::A_GameMenu, "/user/hand/left/input/menu/click"}, // Touch: Y + {A_Recenter, "/user/hand/left/input/menu/click"}, // Touch: Y + {A_MenuSelect, "/user/hand/right/input/select/click"}, // Touch: A + {A_MenuBack, "/user/hand/right/input/menu/click"}, // Touch: B + }; + mXRInput->suggestBindings(ActionSet::Gameplay, simpleProfilePath, simpleGameplayBindings); + mXRInput->suggestBindings(ActionSet::GUI, simpleProfilePath, simpleGUIBindings); + } + + void VRInputManager::suggestBindingsOculusTouch() + { + std::string controllerProfilePath = "/interaction_profiles/oculus/touch_controller"; + + // In-game character controls + SuggestedBindings gameplayBindings{ + {A_ActivateTouch, "/user/hand/right/input/squeeze/value"}, + {A_Recenter, "/user/hand/left/input/menu/click"}, + {MWInput::A_Activate, "/user/hand/right/input/squeeze/value"}, + {MWInput::A_AlwaysRun, "/user/hand/left/input/thumbstick/click"}, + {MWInput::A_AutoMove, "/user/hand/right/input/thumbstick/click"}, + {MWInput::A_GameMenu, "/user/hand/left/input/menu/click"}, + {MWInput::A_Inventory, "/user/hand/right/input/b/click"}, + {MWInput::A_Journal, "/user/hand/right/input/b/click"}, + {MWInput::A_Jump, "/user/hand/left/input/trigger/value"}, + {MWInput::A_LookLeftRight, "/user/hand/right/input/thumbstick/x"}, + {MWInput::A_MoveForwardBackward,"/user/hand/left/input/thumbstick/y"}, + {MWInput::A_MoveLeftRight, "/user/hand/left/input/thumbstick/x"}, + {MWInput::A_QuickSave, "/user/hand/left/input/y/click"}, + {MWInput::A_Rest, "/user/hand/left/input/y/click"}, + {MWInput::A_Sneak, "/user/hand/left/input/squeeze/value"}, + {MWInput::A_ToggleDebug, "/user/hand/right/input/thumbstick/click"}, + {MWInput::A_ToggleHUD, "/user/hand/left/input/thumbstick/click"}, + {MWInput::A_ToggleSpell, "/user/hand/left/input/x/click"}, + {MWInput::A_ToggleWeapon, "/user/hand/right/input/a/click"}, + {MWInput::A_Use, "/user/hand/right/input/trigger/value"}, + }; + + // GUI controls + SuggestedBindings GUIBindings{ + {A_MenuUpDown, "/user/hand/right/input/thumbstick/y"}, + {A_MenuLeftRight, "/user/hand/right/input/thumbstick/x"}, + {A_MenuSelect, "/user/hand/right/input/a/click"}, + {A_MenuBack, "/user/hand/right/input/b/click"}, + {MWInput::A_GameMenu, "/user/hand/left/input/menu/click"}, + {MWInput::A_Use, "/user/hand/right/input/trigger/value"}, + {A_Recenter, "/user/hand/left/input/menu/click"}, + }; + + mXRInput->suggestBindings(ActionSet::Gameplay, controllerProfilePath, gameplayBindings); + mXRInput->suggestBindings(ActionSet::GUI, controllerProfilePath, GUIBindings); + } + + void VRInputManager::suggestBindingsHpMixedReality() + { + std::string controllerProfilePath = "/interaction_profiles/hp/mixed_reality_controller"; + + // In-game character controls + SuggestedBindings gameplayBindings{ + {A_ActivateTouch, "/user/hand/right/input/squeeze/value"}, + {A_Recenter, "/user/hand/left/input/menu/click"}, + {MWInput::A_Activate, "/user/hand/right/input/squeeze/value"}, + {MWInput::A_AlwaysRun, "/user/hand/left/input/thumbstick/click"}, + {MWInput::A_AutoMove, "/user/hand/right/input/thumbstick/click"}, + {MWInput::A_GameMenu, "/user/hand/left/input/menu/click"}, + {MWInput::A_Inventory, "/user/hand/right/input/b/click"}, + {MWInput::A_Journal, "/user/hand/right/input/b/click"}, + {MWInput::A_Jump, "/user/hand/left/input/trigger/value"}, + {MWInput::A_LookLeftRight, "/user/hand/right/input/thumbstick/x"}, + {MWInput::A_MoveForwardBackward,"/user/hand/left/input/thumbstick/y"}, + {MWInput::A_MoveLeftRight, "/user/hand/left/input/thumbstick/x"}, + {MWInput::A_QuickSave, "/user/hand/left/input/y/click"}, + {MWInput::A_Rest, "/user/hand/left/input/y/click"}, + {MWInput::A_Sneak, "/user/hand/left/input/squeeze/value"}, + {MWInput::A_ToggleDebug, "/user/hand/right/input/thumbstick/click"}, + {MWInput::A_ToggleHUD, "/user/hand/left/input/thumbstick/click"}, + {MWInput::A_ToggleSpell, "/user/hand/left/input/x/click"}, + {MWInput::A_ToggleWeapon, "/user/hand/right/input/a/click"}, + {MWInput::A_Use, "/user/hand/right/input/trigger/value"}, + }; + + // GUI controls + SuggestedBindings GUIBindings{ + {A_MenuUpDown, "/user/hand/right/input/thumbstick/y"}, + {A_MenuLeftRight, "/user/hand/right/input/thumbstick/x"}, + {A_MenuSelect, "/user/hand/right/input/a/click"}, + {A_MenuBack, "/user/hand/right/input/b/click"}, + {MWInput::A_GameMenu, "/user/hand/left/input/menu/click"}, + {MWInput::A_Use, "/user/hand/right/input/trigger/value"}, + {A_Recenter, "/user/hand/left/input/menu/click"}, + }; + + mXRInput->suggestBindings(ActionSet::Gameplay, controllerProfilePath, gameplayBindings); + mXRInput->suggestBindings(ActionSet::GUI, controllerProfilePath, GUIBindings); + } + + void VRInputManager::suggestBindingsMicrosoftMixedReality() + { + std::string controllerProfilePath = "/interaction_profiles/microsoft/motion_controller"; + + // TODO: Slightly better than the vive wands, but still not good. + + // In-game character controls + SuggestedBindings gameplayBindings{ + //{MWInput::A_AlwaysRun, "/user/hand/left/input/thumbstick/click"}, + //{MWInput::A_AutoMove, "/user/hand/right/input/thumbstick/click"}, + //{MWInput::A_ToggleDebug, "/user/hand/right/input/thumbstick/click"}, + //{MWInput::A_ToggleHUD, "/user/hand/left/input/thumbstick/click"}, + {A_ActivateTouch, "/user/hand/right/input/squeeze/click"}, + {A_Recenter, "/user/hand/left/input/menu/click"}, + {MWInput::A_Activate, "/user/hand/right/input/squeeze/click"}, + {MWInput::A_GameMenu, "/user/hand/left/input/menu/click"}, + {MWInput::A_Inventory, "/user/hand/right/input/thumbstick/click"}, + {MWInput::A_Journal, "/user/hand/right/input/thumbstick/click"}, + {MWInput::A_Jump, "/user/hand/left/input/trigger/value"}, + {MWInput::A_LookLeftRight, "/user/hand/right/input/thumbstick/x"}, + {MWInput::A_MoveForwardBackward,"/user/hand/left/input/thumbstick/y"}, + {MWInput::A_MoveLeftRight, "/user/hand/left/input/thumbstick/x"}, + {MWInput::A_QuickSave, "/user/hand/left/input/thumbstick/click"}, + {MWInput::A_Rest, "/user/hand/left/input/thumbstick/click"}, + {MWInput::A_Sneak, "/user/hand/left/input/squeeze/click"}, + {MWInput::A_ToggleSpell, "/user/hand/left/input/trackpad/click"}, + {MWInput::A_ToggleWeapon, "/user/hand/right/input/trackpad/click"}, + {MWInput::A_Use, "/user/hand/right/input/trigger/value"}, + }; + + // GUI controls + SuggestedBindings GUIBindings{ + {A_MenuUpDown, "/user/hand/right/input/thumbstick/y"}, + {A_MenuLeftRight, "/user/hand/right/input/thumbstick/x"}, + {A_MenuSelect, "/user/hand/right/input/trackpad/click"}, + {A_MenuBack, "/user/hand/left/input/trackpad/click"}, + {MWInput::A_GameMenu, "/user/hand/left/input/menu/click"}, + {MWInput::A_Use, "/user/hand/right/input/trigger/value"}, + {A_Recenter, "/user/hand/left/input/menu/click"}, + }; + + mXRInput->suggestBindings(ActionSet::Gameplay, controllerProfilePath, gameplayBindings); + mXRInput->suggestBindings(ActionSet::GUI, controllerProfilePath, GUIBindings); + } + + void VRInputManager::suggestBindingsIndex() + { + std::string controllerProfilePath = "/interaction_profiles/valve/index_controller"; + // In-game character controls + SuggestedBindings gameplayBindings{ + {A_ActivateTouch, "/user/hand/right/input/squeeze/value"}, + {A_Recenter, "/user/hand/left/input/thumbstick/click"}, + {MWInput::A_Activate, "/user/hand/right/input/squeeze/value"}, + //{MWInput::A_AlwaysRun, "/user/hand/left/input/thumbstick/click"}, + //{MWInput::A_AutoMove, "/user/hand/right/input/thumbstick/click"}, + {MWInput::A_GameMenu, "/user/hand/left/input/thumbstick/click"}, + {MWInput::A_Inventory, "/user/hand/right/input/b/click"}, + {MWInput::A_Journal, "/user/hand/right/input/b/click"}, + {MWInput::A_Jump, "/user/hand/left/input/trigger/value"}, + {MWInput::A_LookLeftRight, "/user/hand/right/input/thumbstick/x"}, + {MWInput::A_MoveForwardBackward,"/user/hand/left/input/thumbstick/y"}, + {MWInput::A_MoveLeftRight, "/user/hand/left/input/thumbstick/x"}, + {MWInput::A_QuickSave, "/user/hand/left/input/b/click"}, + {MWInput::A_Rest, "/user/hand/left/input/b/click"}, + {MWInput::A_Sneak, "/user/hand/left/input/squeeze/value"}, + //{MWInput::A_ToggleDebug, "/user/hand/right/input/thumbstick/click"}, + //{MWInput::A_ToggleHUD, "/user/hand/left/input/thumbstick/click"}, + {MWInput::A_ToggleSpell, "/user/hand/left/input/a/click"}, + {MWInput::A_ToggleWeapon, "/user/hand/right/input/a/click"}, + {MWInput::A_Use, "/user/hand/right/input/trigger/value"}, + }; + + // GUI controls + SuggestedBindings GUIBindings{ + {A_MenuUpDown, "/user/hand/right/input/thumbstick/y"}, + {A_MenuLeftRight, "/user/hand/right/input/thumbstick/x"}, + {A_MenuSelect, "/user/hand/right/input/a/click"}, + {A_MenuBack, "/user/hand/right/input/b/click"}, + {MWInput::A_GameMenu, "/user/hand/left/input/thumbstick/click"}, + {MWInput::A_Use, "/user/hand/right/input/trigger/value"}, + {A_Recenter, "/user/hand/left/input/thumbstick/click"}, + }; + + mXRInput->suggestBindings(ActionSet::Gameplay, controllerProfilePath, gameplayBindings); + mXRInput->suggestBindings(ActionSet::GUI, controllerProfilePath, GUIBindings); + } + + void VRInputManager::suggestBindingsVive() + { + std::string controllerProfilePath = "/interaction_profiles/htc/vive_controller"; + + // TODO: I Didn't realize the vive wands were so bad. We don't have NEARLY enough actions available. + + // In-game character controls + SuggestedBindings gameplayBindings{ + //{MWInput::A_AlwaysRun, "/user/hand/left/input/thumbstick/click"}, + //{MWInput::A_AutoMove, "/user/hand/right/input/thumbstick/click"}, + //{MWInput::A_Inventory, "/user/hand/right/input/b/click"}, + //{MWInput::A_Journal, "/user/hand/right/input/b/click"}, + //{MWInput::A_QuickSave, "/user/hand/left/input/b/click"}, + //{MWInput::A_Rest, "/user/hand/left/input/b/click"}, + //{MWInput::A_ToggleDebug, "/user/hand/right/input/thumbstick/click"}, + //{MWInput::A_ToggleHUD, "/user/hand/left/input/thumbstick/click"}, + {A_ActivateTouch, "/user/hand/right/input/squeeze/click"}, + {A_Recenter, "/user/hand/left/input/menu/click"}, + {MWInput::A_Activate, "/user/hand/right/input/squeeze/click"}, + {MWInput::A_GameMenu, "/user/hand/left/input/menu/click"}, + {MWInput::A_Jump, "/user/hand/left/input/trigger/value"}, + {MWInput::A_LookLeftRight, "/user/hand/right/input/trackpad/x"}, + {MWInput::A_MoveForwardBackward,"/user/hand/left/input/trackpad/y"}, + {MWInput::A_MoveLeftRight, "/user/hand/left/input/trackpad/x"}, + {MWInput::A_Sneak, "/user/hand/left/input/squeeze/click"}, + {MWInput::A_ToggleSpell, "/user/hand/left/input/trackpad/click"}, + {MWInput::A_ToggleWeapon, "/user/hand/right/input/trackpad/click"}, + {MWInput::A_Use, "/user/hand/right/input/trigger/value"}, + }; + + // GUI controls + SuggestedBindings GUIBindings{ + {A_MenuUpDown, "/user/hand/right/input/trackpad/y"}, + {A_MenuLeftRight, "/user/hand/right/input/trackpad/x"}, + {A_MenuSelect, "/user/hand/right/input/trackpad/click"}, + {A_MenuBack, "/user/hand/left/input/trackpad/click"}, + {MWInput::A_GameMenu, "/user/hand/left/input/menu/click"}, + {MWInput::A_Use, "/user/hand/right/input/trigger/value"}, + {A_Recenter, "/user/hand/left/input/menu/click"}, + }; + + mXRInput->suggestBindings(ActionSet::Gameplay, controllerProfilePath, gameplayBindings); + mXRInput->suggestBindings(ActionSet::GUI, controllerProfilePath, GUIBindings); + } + + void VRInputManager::suggestBindingsXboxController() + { + //TODO + } + void VRInputManager::requestRecenter() { mShouldRecenter = true; @@ -193,106 +448,19 @@ namespace MWVR controllerBindingsFile, grab) , mXRInput(new OpenXRInput) - , mHapticsEnabled{Settings::Manager::getBool("haptics enabled", "VR")} + , mHapticsEnabled{ Settings::Manager::getBool("haptics enabled", "VR") } { - std::string oculusTouchProfilePath = "/interaction_profiles/oculus/touch_controller"; - // Set up default bindings for the oculus + auto xr = MWVR::Environment::get().getManager(); - /* - Oculus Bindings: - L-Squeeze: - Hold: Sneak + suggestBindingsSimple(); + suggestBindingsOculusTouch(); + suggestBindingsMicrosoftMixedReality(); + suggestBindingsIndex(); + suggestBindingsVive(); + suggestBindingsXboxController(); - R-Squeeze: - Hold: Enable Pointer - - L-Trigger: - Press: Jump - - R-Trigger: - IF POINTER: - Activate - ELSE: - Use - - L-Thumbstick: - X-Axis: MoveForwardBackward - Y-Axis: MoveLeftRight - Button: - Press: AlwaysRun - Long: ToggleHUD - Touch: - - R-Thumbstick: - X-Axis: LookLeftRight - Y-Axis: - Button: - Press: AutoMove - Long: ToggleDebug - Touch: - - X: - Press: Toggle Spell - Long: - Y: - Press: Rest - Long: Quick Save - A: - Press: Toggle Weapon - Long: - B: - Press: Inventory - Long: Journal - - Menu: - Press: GameMenu - Long: Recenter on player and reset GUI - - */ - { - // In-game character controls - SuggestedBindings oculusTouchGameplayBindings{ - {MWInput::A_LookLeftRight, ActionPath::ThumbstickX, Side::RIGHT_SIDE}, - {MWInput::A_MoveLeftRight, ActionPath::ThumbstickX, Side::LEFT_SIDE}, - {MWInput::A_MoveForwardBackward, ActionPath::ThumbstickY, Side::LEFT_SIDE}, - {MWInput::A_Activate, ActionPath::Squeeze, Side::RIGHT_SIDE}, - {MWInput::A_Use, ActionPath::Trigger, Side::RIGHT_SIDE}, - {MWInput::A_Jump, ActionPath::Trigger, Side::LEFT_SIDE}, - {MWInput::A_ToggleWeapon, ActionPath::A, Side::RIGHT_SIDE}, - {MWInput::A_ToggleSpell, ActionPath::X, Side::LEFT_SIDE}, - //{*mCycleSpellLeft, mThumbstickClickPath, Side::LEFT_SIDE}, - //{*mCycleSpellRight, mThumbstickClickPath, Side::RIGHT_SIDE}, - //{*mCycleWeaponLeft, mThumbstickClickPath, Side::LEFT_SIDE}, - //{*mCycleWeaponRight, mThumbstickClickPath, Side::RIGHT_SIDE}, - {MWInput::A_AlwaysRun, ActionPath::ThumbstickClick, Side::LEFT_SIDE}, - {MWInput::A_AutoMove, ActionPath::ThumbstickClick, Side::RIGHT_SIDE}, - {MWInput::A_ToggleHUD, ActionPath::ThumbstickClick, Side::LEFT_SIDE}, - {MWInput::A_ToggleDebug, ActionPath::ThumbstickClick, Side::RIGHT_SIDE}, - {MWInput::A_Sneak, ActionPath::Squeeze, Side::LEFT_SIDE}, - {MWInput::A_Inventory, ActionPath::B, Side::RIGHT_SIDE}, - {MWInput::A_Rest, ActionPath::Y, Side::LEFT_SIDE}, - {MWInput::A_Journal, ActionPath::B, Side::RIGHT_SIDE}, - {MWInput::A_QuickSave, ActionPath::Y, Side::LEFT_SIDE}, - {MWInput::A_GameMenu, ActionPath::Menu, Side::LEFT_SIDE}, - {A_Recenter, ActionPath::Menu, Side::LEFT_SIDE}, - {A_ActivateTouch, ActionPath::Squeeze, Side::RIGHT_SIDE}, - }; - - mXRInput->suggestBindings(ActionSet::Gameplay, oculusTouchProfilePath, oculusTouchGameplayBindings); - - // GUI controls - SuggestedBindings oculusTouchGUIBindings{ - {A_MenuUpDown, ActionPath::ThumbstickY, Side::RIGHT_SIDE}, - {A_MenuLeftRight, ActionPath::ThumbstickX, Side::RIGHT_SIDE}, - {A_MenuSelect, ActionPath::A, Side::RIGHT_SIDE}, - {A_MenuBack, ActionPath::B, Side::RIGHT_SIDE}, - {MWInput::A_GameMenu, ActionPath::Menu, Side::LEFT_SIDE}, - {MWInput::A_Use, ActionPath::Trigger, Side::RIGHT_SIDE}, - {A_Recenter, ActionPath::Menu, Side::LEFT_SIDE}, - }; - - mXRInput->suggestBindings(ActionSet::GUI, oculusTouchProfilePath, oculusTouchGUIBindings); - } + if (xr->xrExtensionIsEnabled(XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME)) + suggestBindingsHpMixedReality(); mXRInput->attachActionSets(); } diff --git a/apps/openmw/mwvr/vrinputmanager.hpp b/apps/openmw/mwvr/vrinputmanager.hpp index 8beb64d6b..4d79d80ae 100644 --- a/apps/openmw/mwvr/vrinputmanager.hpp +++ b/apps/openmw/mwvr/vrinputmanager.hpp @@ -73,6 +73,15 @@ namespace MWVR void applyHapticsLeftHand(float intensity) override; void applyHapticsRightHand(float intensity) override; + private: + void suggestBindingsSimple(); + void suggestBindingsOculusTouch(); + void suggestBindingsHpMixedReality(); + void suggestBindingsMicrosoftMixedReality(); + void suggestBindingsIndex(); + void suggestBindingsVive(); + void suggestBindingsXboxController(); + std::unique_ptr mXRInput; std::unique_ptr mRealisticCombat; Pose mHeadPose{}; diff --git a/apps/openmw/mwvr/vrsession.cpp b/apps/openmw/mwvr/vrsession.cpp index 92f8a3b46..39cbd64db 100644 --- a/apps/openmw/mwvr/vrsession.cpp +++ b/apps/openmw/mwvr/vrsession.cpp @@ -1,3 +1,5 @@ +#include "vrsession.hpp" +#include "vrgui.hpp" #include "vrenvironment.hpp" #include "vrinputmanager.hpp" #include "openxrmanager.hpp" @@ -10,21 +12,12 @@ #include #include -#include - -#include -#include -#include -#include - #include #include #include #include #include -#include "vrsession.hpp" -#include "vrgui.hpp" #include #include