From e573a260cbfc56973a2eb39ef0553ea020dc5122 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Sun, 8 Mar 2020 14:14:24 +0100 Subject: [PATCH] Rudimentary menu interactions --- apps/openmw/mwbase/world.hpp | 11 +++- apps/openmw/mwmechanics/character.cpp | 12 ----- apps/openmw/mwrender/renderingmanager.cpp | 5 +- apps/openmw/mwrender/renderingmanager.hpp | 1 + apps/openmw/mwvr/openxranimation.cpp | 14 +++-- apps/openmw/mwvr/openxrenvironment.cpp | 16 +++++- apps/openmw/mwvr/openxrenvironment.hpp | 7 ++- apps/openmw/mwvr/openxrinputmanager.cpp | 66 +++++++++++++++++++---- apps/openmw/mwvr/openxrinputmanager.hpp | 3 +- apps/openmw/mwvr/openxrmanagerimpl.cpp | 4 +- apps/openmw/mwworld/worldimp.cpp | 15 +++--- apps/openmw/mwworld/worldimp.hpp | 4 +- 12 files changed, 114 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index e3049ae7f..5a57c5e6b 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include @@ -22,6 +22,7 @@ namespace osg class Matrixf; class Quat; class Image; + class Node; } namespace Loading @@ -97,6 +98,12 @@ namespace MWBase ESM::CellId dest; }; + using IntersectedObject = std::tuple< + MWWorld::Ptr, + osg::Node*, + osg::Vec3f + >; + World() {} virtual ~World() {} @@ -261,7 +268,7 @@ namespace MWBase virtual MWWorld::Ptr getFacedObject() = 0; ///< Return pointer to the object the player is looking at, if it is within activation range - virtual std::pair getPointedAtObject() = 0; + virtual IntersectedObject getPointedAtObject() = 0; ///< Return pointer to the object and/or node the player is currently pointing at virtual float getDistanceToFacedObject() = 0; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3e4525eeb..572435b49 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1881,18 +1881,6 @@ bool CharacterController::updateWeaponState(CharacterState& idle) mAnimation->setAccurateAiming(mUpperBodyState > UpperCharState_WeapEquiped); -#ifdef USE_OPENXR - if (mPtr == getPlayer()) - { - auto xrAnimation = dynamic_cast(mAnimation); - if (xrAnimation) - { - bool pointing = MWBase::Environment::get().getWorld()->getPlayer().getPointing(); - xrAnimation->setPointForward(pointing); - } - } -#endif - return forcestateupdate; } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c5e473a29..5e157b33b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -69,6 +69,7 @@ #ifdef USE_OPENXR #include "../mwvr/openxranimation.hpp" +#include "../mwvr/openxrenvironment.hpp" #endif namespace @@ -1025,6 +1026,7 @@ namespace MWRender result.mHit = true; osgUtil::LineSegmentIntersector::Intersection intersection = intersector->getFirstIntersection(); + result.mHitPointLocal = intersection.getLocalIntersectPoint(); result.mHitPointWorld = intersection.getWorldIntersectPoint(); result.mHitNormalWorld = intersection.getWorldIntersectNormal(); result.mRatio = intersection.ratio; @@ -1163,7 +1165,8 @@ namespace MWRender void RenderingManager::renderPlayer(const MWWorld::Ptr &player) { #ifdef USE_OPENXR - mPlayerAnimation = new MWVR::OpenXRAnimation(player, player.getRefData().getBaseNode(), mResourceSystem, false, nullptr); + MWVR::OpenXREnvironment::get().setPlayerAnimation(new MWVR::OpenXRAnimation(player, player.getRefData().getBaseNode(), mResourceSystem, false, nullptr)); + mPlayerAnimation = MWVR::OpenXREnvironment::get().getPlayerAnimation(); #else mPlayerAnimation = new NpcAnimation(player, player.getRefData().getBaseNode(), mResourceSystem, 0, NpcAnimation::VM_Normal, mFirstPersonFieldOfView); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index cf45bc64e..04c736ed5 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -151,6 +151,7 @@ namespace MWRender bool mHit; osg::Vec3f mHitNormalWorld; osg::Vec3f mHitPointWorld; + osg::Vec3f mHitPointLocal; MWWorld::Ptr mHitObject; osg::Node* mHitNode; float mRatio; diff --git a/apps/openmw/mwvr/openxranimation.cpp b/apps/openmw/mwvr/openxranimation.cpp index 720e9fc33..e893108f5 100644 --- a/apps/openmw/mwvr/openxranimation.cpp +++ b/apps/openmw/mwvr/openxranimation.cpp @@ -184,11 +184,17 @@ void FingerController::operator()(osg::Node* node, osg::NodeVisitor* nv) { // Get distance to pointer intersection auto pat = pointerTransform->asTransform()->asPositionAttitudeTransform(); - // TODO: Using the cached value from the input manager makes this off by one frame - float intersected_distance = MWBase::Environment::get().getWorld()->getDistanceToPointedAtObject(); + auto* world = MWBase::Environment::get().getWorld(); + if (world) + { + // TODO: Using the cached value from the input manager makes this off by one frame + // So do one otherwise redundant intersection here. + world->getPointedAtObject(); + float intersected_distance = world->getDistanceToPointedAtObject(); - // Stretch beam to point of intersection. - pat->setScale(osg::Vec3(1.f, 1.f, intersected_distance)); + // Stretch beam to point of intersection. + pat->setScale(osg::Vec3(.25f, .25f, intersected_distance)); + } } } diff --git a/apps/openmw/mwvr/openxrenvironment.cpp b/apps/openmw/mwvr/openxrenvironment.cpp index d9843022b..878383714 100644 --- a/apps/openmw/mwvr/openxrenvironment.cpp +++ b/apps/openmw/mwvr/openxrenvironment.cpp @@ -2,6 +2,7 @@ #include +#include "openxranimation.hpp" #include "openxrinputmanager.hpp" #include "openxrsession.hpp" #include "openxrmenu.hpp" @@ -31,6 +32,9 @@ void MWVR::OpenXREnvironment::cleanup() if (mMenuManager) delete mMenuManager; mMenuManager = nullptr; + if (mPlayerAnimation) + delete mPlayerAnimation; + mPlayerAnimation = nullptr; if (mViewer) delete mViewer; mViewer = nullptr; @@ -39,7 +43,7 @@ void MWVR::OpenXREnvironment::cleanup() mOpenXRManager = nullptr; } -const MWVR::OpenXREnvironment& MWVR::OpenXREnvironment::get() +MWVR::OpenXREnvironment& MWVR::OpenXREnvironment::get() { assert (sThis); return *sThis; @@ -74,6 +78,16 @@ void MWVR::OpenXREnvironment::setMenuManager(MWVR::OpenXRMenuManager* menuManage mMenuManager = menuManager; } +MWVR::OpenXRAnimation* MWVR::OpenXREnvironment::getPlayerAnimation() const +{ + return mPlayerAnimation; +} + +void MWVR::OpenXREnvironment::setPlayerAnimation(MWVR::OpenXRAnimation* xrAnimation) +{ + mPlayerAnimation = xrAnimation; +} + MWVR::OpenXRViewer* MWVR::OpenXREnvironment::getViewer() const { diff --git a/apps/openmw/mwvr/openxrenvironment.hpp b/apps/openmw/mwvr/openxrenvironment.hpp index f4939307c..a57525792 100644 --- a/apps/openmw/mwvr/openxrenvironment.hpp +++ b/apps/openmw/mwvr/openxrenvironment.hpp @@ -3,6 +3,7 @@ namespace MWVR { + class OpenXRAnimation; class OpenXRInputManager; class OpenXRSession; class OpenXRMenuManager; @@ -35,7 +36,7 @@ namespace MWVR void cleanup(); ///< Delete all mwvr-subsystems. - static const OpenXREnvironment& get(); + static OpenXREnvironment& get(); ///< Return instance of this class. MWVR::OpenXRInputManager* getInputManager() const; @@ -47,6 +48,9 @@ namespace MWVR MWVR::OpenXRMenuManager* getMenuManager() const; void setMenuManager(MWVR::OpenXRMenuManager* xrMenuManager); + MWVR::OpenXRAnimation* getPlayerAnimation() const; + void setPlayerAnimation(MWVR::OpenXRAnimation* xrAnimation); + MWVR::OpenXRSession* getSession() const; void setSession(MWVR::OpenXRSession* xrSession); @@ -62,6 +66,7 @@ namespace MWVR private: MWVR::OpenXRSession* mSession{ nullptr }; MWVR::OpenXRMenuManager* mMenuManager{ nullptr }; + MWVR::OpenXRAnimation* mPlayerAnimation{ nullptr }; MWVR::OpenXRViewer* mViewer{ nullptr }; MWVR::OpenXRManager* mOpenXRManager{ nullptr }; float mUnitsPerMeter{ 1.f }; diff --git a/apps/openmw/mwvr/openxrinputmanager.cpp b/apps/openmw/mwvr/openxrinputmanager.cpp index 4f07cd460..578976762 100644 --- a/apps/openmw/mwvr/openxrinputmanager.cpp +++ b/apps/openmw/mwvr/openxrinputmanager.cpp @@ -1,3 +1,4 @@ +#include "openxranimation.hpp" #include "openxrinputmanager.hpp" #include "openxrenvironment.hpp" #include "openxrmanager.hpp" @@ -625,10 +626,6 @@ namespace MWVR { mActionEvents.emplace_back(OpenXRActionEvent{ MWInput::InputManager::A_Inventory, true }); } - if (mActivate.actionOnPress()) - { - mActionEvents.emplace_back(OpenXRActionEvent{ MWInput::InputManager::A_Activate, true }); - } if (mJump.actionOnPress()) { mActionEvents.emplace_back(OpenXRActionEvent{ MWInput::InputManager::A_Jump, true }); @@ -637,6 +634,12 @@ namespace MWVR { mActionEvents.emplace_back(OpenXRActionEvent{ MWInput::InputManager::A_QuickMenu, true }); } + + // Actions that activate on release + if (mActivate.actionChanged()) + { + mActionEvents.emplace_back(OpenXRActionEvent{ MWInput::InputManager::A_Activate, mActivate.actionOnPress() }); + } // Actions that hold with the button if (mUse.actionChanged()) @@ -749,9 +752,16 @@ namespace MWVR return mXRInput->getHandPoses(time, space); } - void OpenXRInputManager::showActivationIndication(bool show) + void OpenXRInputManager::updateActivationIndication(void) { - mPlayer->setPointing(show); + bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); + bool show = guiMode | mActivationIndication; + if (mPlayer) + mPlayer->setPointing(show); + + auto* playerAnimation = OpenXREnvironment::get().getPlayerAnimation(); + if (playerAnimation) + playerAnimation->setPointForward(show); } OpenXRInputManager::OpenXRInputManager( @@ -801,11 +811,30 @@ namespace MWVR { mXRInput->updateControls(); + auto* world = MWBase::Environment::get().getWorld(); if (world) { auto pointedAt = world->getPointedAtObject(); // TODO: Left off here + + auto* node = std::get<1>(pointedAt); + if (node) + { + + int w, h; + SDL_GetWindowSize(mWindow, &w, &h); + + osg::Vec3 local = std::get<2>(pointedAt); + local.x() = (local.x() + 1.f) / 2.f; + local.y() = 1.f - (local.y() + 1.f) / 2.f; + + + mGuiCursorX = mInvUiScalingFactor * (local.x() * w); + mGuiCursorY = mInvUiScalingFactor * (local.y() * h); + + MyGUI::InputManager::getInstance().injectMouseMove(int(mGuiCursorX), int(mGuiCursorY), 0); + } } OpenXRActionEvent event{}; @@ -814,6 +843,8 @@ namespace MWVR processEvent(event); } + updateActivationIndication(); + MWInput::InputManager::update(dt, disableControls, disableEvents); bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); @@ -831,7 +862,6 @@ namespace MWVR switch (event.action) { case A_GameMenu: - Log(Debug::Verbose) << "A_GameMenu"; toggleMainMenu(); // Explicitly request position update here so that the player can move the menu // using the menu key when the menu can't be toggled. @@ -848,7 +878,14 @@ namespace MWVR break; case A_Activate: resetIdleTime(); - activate(); + { + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + { + // Do nothing + } + else if(!event.onPress) + activate(); + } break; // TODO: Movement //case A_MoveLeft: @@ -964,10 +1001,19 @@ namespace MWVR mAttemptJump = true; break; case A_Use: - mInputBinder->getChannel(A_Use)->setValue(event.onPress); + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + { + SDL_MouseButtonEvent arg; + if (event.onPress) + mousePressed(arg, SDL_BUTTON_LEFT); + else + mouseReleased(arg, SDL_BUTTON_LEFT); + } + else + mInputBinder->getChannel(A_Use)->setValue(event.onPress); break; case OpenXRInput::A_ActivateTouch: - showActivationIndication(event.onPress); + mActivationIndication = event.onPress; break; default: Log(Debug::Warning) << "Unhandled XR action " << event.action; diff --git a/apps/openmw/mwvr/openxrinputmanager.hpp b/apps/openmw/mwvr/openxrinputmanager.hpp index 1aac75867..a7a2042d4 100644 --- a/apps/openmw/mwvr/openxrinputmanager.hpp +++ b/apps/openmw/mwvr/openxrinputmanager.hpp @@ -43,12 +43,13 @@ namespace MWVR PoseSet getHandPoses(int64_t time, TrackedSpace space); - void showActivationIndication(bool show); + void updateActivationIndication(void); std::unique_ptr mXRInput; Pose mPreviousHeadPose{}; osg::Vec3 mHeadOffset{ 0,0,0 }; bool mRecenter{ true }; + bool mActivationIndication{ false }; float mYaw{ 0.f }; float mVrAngles[3]{ 0.f,0.f,0.f }; diff --git a/apps/openmw/mwvr/openxrmanagerimpl.cpp b/apps/openmw/mwvr/openxrmanagerimpl.cpp index 2b41a806d..1fe4d96a8 100644 --- a/apps/openmw/mwvr/openxrmanagerimpl.cpp +++ b/apps/openmw/mwvr/openxrmanagerimpl.cpp @@ -58,7 +58,7 @@ namespace MWVR createInfo.enabledExtensionCount = extensions.size(); createInfo.enabledExtensionNames = extensions.data(); - strcpy(createInfo.applicationInfo.applicationName, "Boo"); + strcpy(createInfo.applicationInfo.applicationName, "openmw_vr"); createInfo.applicationInfo.apiVersion = XR_CURRENT_API_VERSION; CHECK_XRCMD(xrCreateInstance(&createInfo, &mInstance)); assert(mInstance); @@ -504,7 +504,7 @@ namespace MWVR MWBase::Environment::get().getWorld()->getStore().get().find(ref->mBase->mRace); bool isMale = ref->mBase->isMale(); float charHeightFactor = isMale ? race->mData.mHeight.mMale : race->mData.mHeight.mFemale; - float charHeightBase = 2.f; + float charHeightBase = 1.8f; float charHeight = charHeightBase * charHeightFactor; // TODO: Player height should be configurable // For now i'm just using my own diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8e55b2ea3..584ecb086 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1113,7 +1113,7 @@ namespace MWWorld return facedObject; } - std::pair World::getPointedAtObject() + World::IntersectedObject World::getPointedAtObject() { if (MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager()->isConsoleMode()) @@ -1123,10 +1123,10 @@ namespace MWWorld else { auto pointedAtObject = getPointedAtObject(getActivationDistancePlusTelekinesis(), true); - - if (!pointedAtObject.first.isEmpty() && !pointedAtObject.first.getClass().allowTelekinesis(pointedAtObject.first) + auto ptr = std::get<0>(pointedAtObject); + if (!ptr.isEmpty() && !ptr.getClass().allowTelekinesis(ptr) && mDistanceToFacedObject > getMaxActivationDistance() && !MWBase::Environment::get().getWindowManager()->isGuiMode()) - return std::pair(); + return IntersectedObject(); return pointedAtObject; } } @@ -2070,7 +2070,7 @@ namespace MWWorld return facedObject; } - std::pair World::getPointedAtObject(float maxDistance, bool ignorePlayer) + World::IntersectedObject World::getPointedAtObject(float maxDistance, bool ignorePlayer) { auto sceneRoot = mRendering->getLightRoot(); @@ -2103,11 +2103,10 @@ namespace MWWorld else // Leave a very large but not too large number to permit visualizing a beam going into "infinity" mDistanceToPointedAtObject = 10000.f; - - return { rayToObject.mHitObject, rayToObject.mHitNode }; + return { rayToObject.mHitObject, rayToObject.mHitNode, rayToObject.mHitPointLocal }; } - return std::pair(); + return IntersectedObject(); } bool World::isCellExterior() const diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index ac59c037e..54fedb904 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -140,7 +140,7 @@ namespace MWWorld MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer=true); - std::pair getPointedAtObject(float maxDistance, bool ignorePlayer=true); + IntersectedObject getPointedAtObject(float maxDistance, bool ignorePlayer=true); public: // FIXME void addContainerScripts(const Ptr& reference, CellStore* cell) override; @@ -377,7 +377,7 @@ namespace MWWorld MWWorld::Ptr getFacedObject() override; ///< Return pointer to the object the player is looking at, if it is within activation range - std::pair getPointedAtObject() override; + IntersectedObject getPointedAtObject() override; ///< Return pointer to the object and/or node the player is currently pointing at float getDistanceToFacedObject() override;