diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index e8ae61fe5..578eefc54 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -53,7 +53,7 @@ namespace MWWorld namespace MWGui { class Layout; - + class DragAndDrop; class Console; class SpellWindow; class TradeWindow; @@ -226,6 +226,7 @@ namespace MWBase virtual void showCrosshair(bool show) = 0; virtual bool getSubtitlesEnabled() = 0; virtual bool toggleHud() = 0; + virtual MWGui::DragAndDrop& getDragAndDrop(void) = 0; virtual void disallowMouse() = 0; virtual void allowMouse() = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 5a57c5e6b..e501109c1 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -54,6 +54,7 @@ namespace MWRender { class Animation; class RenderingManager; + struct RayResult; } namespace MWMechanics @@ -98,12 +99,6 @@ namespace MWBase ESM::CellId dest; }; - using IntersectedObject = std::tuple< - MWWorld::Ptr, - osg::Node*, - osg::Vec3f - >; - World() {} virtual ~World() {} @@ -268,11 +263,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 IntersectedObject getPointedAtObject() = 0; - ///< Return pointer to the object and/or node the player is currently pointing at - virtual float getDistanceToFacedObject() = 0; - virtual float getDistanceToPointedAtObject() = 0; virtual float getMaxActivationDistance() = 0; @@ -638,6 +629,27 @@ namespace MWBase virtual osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const = 0; virtual bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const = 0; + +#ifdef USE_OPENXR + using IntersectedObject = std::tuple< + MWWorld::Ptr, + osg::Node*, + osg::Vec3f + >; + + virtual float getDistanceToPointedAtObject() = 0; + ///< Return the distance to the object and/or node the player is currently pointing at + virtual void getPointedAtObject(MWRender::RayResult& result) = 0; + ///< Return pointer to the object and/or node the player is currently pointing at + + virtual MWWorld::Ptr placeObject(const MWWorld::ConstPtr& object, int amount) = 0; + ///< copy and place an object into the gameworld where the player is currently pointing + /// @param object + /// @param number of objects to place + + virtual bool canPlaceObject() = 0; + ///< @return true if it is possible to place on object where the player is currently pointing +#endif }; } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 4f51dac04..6564f3fc0 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -270,6 +270,7 @@ namespace MWGui } } + // XR-TODO: Implement equivalent void HUD::onWorldMouseOver(MyGUI::Widget* _sender, int x, int y) { if (mDragAndDrop->mIsOnDragAndDrop) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 0524945fd..935c35f6d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -113,6 +113,11 @@ #include "keyboardnavigation.hpp" #include "resourceskin.hpp" +#ifdef USE_OPENXR +#include "../mwvr/openxrenvironment.hpp" +#include "../mwvr/openxrmenu.hpp" +#endif + namespace { @@ -175,6 +180,7 @@ namespace MWGui , mHudEnabled(true) , mCursorVisible(true) , mCursorActive(false) + , mVideoEnabled(false) , mPlayerBounty(-1) , mPlayerName() , mPlayerRaceId() @@ -872,6 +878,8 @@ namespace MWGui } } + mVideoEnabled = false; + popGuiMode(); } @@ -1532,6 +1540,11 @@ namespace MWGui updateVisible(); } + DragAndDrop& WindowManager::getDragAndDrop(void) + { + return *mDragAndDrop; + } + void WindowManager::forceHide(GuiWindow wnd) { mForceHidden = (GuiWindow)(mForceHidden | wnd); @@ -1549,7 +1562,8 @@ namespace MWGui return !mGuiModes.empty() || isConsoleMode() || - (mMessageBoxManager && mMessageBoxManager->isInteractiveMessageBox()); + (mMessageBoxManager && mMessageBoxManager->isInteractiveMessageBox()) || + mVideoEnabled; } bool WindowManager::isConsoleMode() const @@ -1870,8 +1884,15 @@ namespace MWGui void WindowManager::playVideo(const std::string &name, bool allowSkipping) { + mVideoEnabled = true; mVideoWidget->playVideo("video\\" + name); +#ifdef USE_OPENXR + // Temporary hack to force update of menu placement + // (Menu gets recreated next tick) + auto* xrMenuManager = MWVR::OpenXREnvironment::get().getMenuManager(); +#endif + mVideoWidget->eventKeyButtonPressed.clear(); mVideoBackground->eventKeyButtonPressed.clear(); if (allowSkipping) @@ -1902,12 +1923,22 @@ namespace MWGui ~MWSound::Type::Movie & MWSound::Type::Mask ); osg::Timer frameTimer; - while (mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) + while (mVideoEnabled && mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { + double dt = frameTimer.time_s(); frameTimer.setStartTick(); MWBase::Environment::get().getInputManager()->update(dt, true, false); +#ifdef USE_OPENXR + // Temporary hack to force update of menu placement + // (Menu gets recreated next tick) + if (xrMenuManager) + { + xrMenuManager->showMenus(false); + xrMenuManager = nullptr; + } +#endif if (!MWBase::Environment::get().getInputManager()->isWindowVisible()) OpenThreads::Thread::microSleep(5000); @@ -1937,6 +1968,7 @@ namespace MWGui mViewer->getCamera()->setCullMask(oldCullMask); mVideoBackground->setVisible(false); + mVideoEnabled = false; } void WindowManager::sizeVideo(int screenWidth, int screenHeight) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 0b4307ec4..9cb83994f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -168,6 +168,8 @@ namespace MWGui virtual void toggleVisible(GuiWindow wnd); + virtual DragAndDrop& getDragAndDrop(void) override; + virtual void forceHide(MWGui::GuiWindow wnd); virtual void unsetForceHide(MWGui::GuiWindow wnd); @@ -461,6 +463,7 @@ namespace MWGui bool mHudEnabled; bool mCursorVisible; bool mCursorActive; + bool mVideoEnabled; int mPlayerBounty; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5e157b33b..dd729818a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1015,9 +1015,9 @@ namespace MWRender return osg::Vec4f(min_x, min_y, max_x, max_y); } - RenderingManager::RayResult getIntersectionResult (osgUtil::LineSegmentIntersector* intersector) + RayResult getIntersectionResult (osgUtil::LineSegmentIntersector* intersector) { - RenderingManager::RayResult result; + RayResult result; result.mHit = false; result.mRatio = 0; result.mHitNode = nullptr; @@ -1074,7 +1074,7 @@ namespace MWRender return mIntersectionVisitor; } - RenderingManager::RayResult RenderingManager::castRay(const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors) + RayResult RenderingManager::castRay(const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors) { osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::MODEL, origin, dest)); @@ -1085,7 +1085,7 @@ namespace MWRender return getIntersectionResult(intersector); } - RenderingManager::RayResult RenderingManager::castCameraToViewportRay(const float nX, const float nY, float maxDistance, bool ignorePlayer, bool ignoreActors) + RayResult RenderingManager::castCameraToViewportRay(const float nX, const float nY, float maxDistance, bool ignorePlayer, bool ignoreActors) { osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::PROJECTION, nX * 2.f - 1.f, nY * (-2.f) + 1.f)); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 04c736ed5..d644dfb7d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -83,6 +83,19 @@ namespace MWRender class NavMesh; class ActorsPaths; + // Result data of ray cast methods. + // Needs to be declared outside the RenderingManager class to be forward declarable + struct RayResult + { + bool mHit; + osg::Vec3f mHitNormalWorld; + osg::Vec3f mHitPointWorld; + osg::Vec3f mHitPointLocal; + MWWorld::Ptr mHitObject; + osg::Node* mHitNode; + float mRatio; + }; + class RenderingManager : public MWRender::RenderingInterface { public: @@ -146,17 +159,6 @@ namespace MWRender void screenshot(osg::Image* image, int w, int h, osg::Matrixd cameraTransform=osg::Matrixd()); bool screenshot360(osg::Image* image, std::string settingStr); - struct RayResult - { - bool mHit; - osg::Vec3f mHitNormalWorld; - osg::Vec3f mHitPointWorld; - osg::Vec3f mHitPointLocal; - MWWorld::Ptr mHitObject; - osg::Node* mHitNode; - float mRatio; - }; - RayResult castRay(const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors=false); /// Return the object under the mouse cursor / crosshair position, given by nX and nY normalized screen coordinates, diff --git a/apps/openmw/mwvr/openxranimation.cpp b/apps/openmw/mwvr/openxranimation.cpp index e893108f5..cadc129b4 100644 --- a/apps/openmw/mwvr/openxranimation.cpp +++ b/apps/openmw/mwvr/openxranimation.cpp @@ -189,7 +189,8 @@ void FingerController::operator()(osg::Node* node, osg::NodeVisitor* nv) { // TODO: Using the cached value from the input manager makes this off by one frame // So do one otherwise redundant intersection here. - world->getPointedAtObject(); + MWRender::RayResult result; + world->getPointedAtObject(result); float intersected_distance = world->getDistanceToPointedAtObject(); // Stretch beam to point of intersection. diff --git a/apps/openmw/mwvr/openxrinputmanager.cpp b/apps/openmw/mwvr/openxrinputmanager.cpp index a67629735..fde65c460 100644 --- a/apps/openmw/mwvr/openxrinputmanager.cpp +++ b/apps/openmw/mwvr/openxrinputmanager.cpp @@ -26,6 +26,9 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwgui/itemmodel.hpp" +#include "../mwgui/draganddrop.hpp" + #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" @@ -764,14 +767,51 @@ void OpenXRInputManager::updateActivationIndication(void) playerAnimation->setPointForward(show); } + +/** + * Makes it possible to use ItemModel::moveItem to move an item from an inventory to the world. + */ +class DropItemAtPointModel: public MWGui::ItemModel +{ +public: + DropItemAtPointModel(){} + virtual ~DropItemAtPointModel() {} + virtual MWWorld::Ptr copyItem(const MWGui::ItemStack& item, size_t count, bool /*allowAutoEquip*/) + { + MWBase::World* world = MWBase::Environment::get().getWorld(); + + MWWorld::Ptr dropped; + if (world->canPlaceObject()) + dropped = world->placeObject(item.mBase, count); + else + dropped = world->dropObjectOnGround(world->getPlayerPtr(), item.mBase, count); + dropped.getCellRef().setOwner(""); + + return dropped; + } + + virtual void removeItem(const MWGui::ItemStack& item, size_t count) { throw std::runtime_error("removeItem not implemented"); } + virtual ModelIndex getIndex(MWGui::ItemStack item) { throw std::runtime_error("getIndex not implemented"); } + virtual void update() {} + virtual size_t getItemCount() { return 0; } + virtual MWGui::ItemStack getItem(ModelIndex index) { throw std::runtime_error("getItem not implemented"); } + +private: + // Where to drop the item + MWRender::RayResult mIntersection; +}; + void OpenXRInputManager::pointActivation(bool onPress) { auto* world = MWBase::Environment::get().getWorld(); if (world) { - auto pointedAt = world->getPointedAtObject(); - auto* node = std::get<1>(pointedAt); - MWWorld::Ptr ptr = std::get<0>(pointedAt); + MWRender::RayResult pointedAt; + world->getPointedAtObject(pointedAt); + auto* node = pointedAt.mHitNode; + MWWorld::Ptr ptr = pointedAt.mHitObject; + auto& dnd = MWBase::Environment::get().getWindowManager()->getDragAndDrop(); + if (node && node->getName() == "XR Menu Geometry") { // Interseceted with the menu @@ -782,8 +822,21 @@ void OpenXRInputManager::updateActivationIndication(void) else mouseReleased(arg, SDL_BUTTON_LEFT); } - - if (!ptr.isEmpty()) + else if (onPress) + { + // Other actions should only happen on release; + return; + } + else if (dnd.mIsOnDragAndDrop) + { + // Intersected with the world while drag and drop is active + // Drop item into the world + MWBase::Environment::get().getWorld()->breakInvisibility( + MWMechanics::getPlayer()); + DropItemAtPointModel drop; + dnd.drop(&drop, nullptr); + } + else if (!ptr.isEmpty()) { if (mPlayer) { @@ -840,18 +893,18 @@ void OpenXRInputManager::updateActivationIndication(void) { mXRInput->updateControls(); - auto* world = MWBase::Environment::get().getWorld(); if (world) { - auto pointedAt = world->getPointedAtObject(); - auto* node = std::get<1>(pointedAt); + MWRender::RayResult pointedAt; + world->getPointedAtObject(pointedAt); + auto* node = pointedAt.mHitNode; if (node) { int w, h; SDL_GetWindowSize(mWindow, &w, &h); - osg::Vec3 local = std::get<2>(pointedAt); + osg::Vec3 local = pointedAt.mHitPointLocal; local.x() = (local.x() + 1.f) / 2.f; local.y() = 1.f - (local.y() + 1.f) / 2.f; @@ -1027,7 +1080,7 @@ void OpenXRInputManager::updateActivationIndication(void) mAttemptJump = true; break; case A_Use: - if (mActivationIndication | MWBase::Environment::get().getWindowManager()->isGuiMode()) + if (mActivationIndication || MWBase::Environment::get().getWindowManager()->isGuiMode()) pointActivation(event.onPress); else mInputBinder->getChannel(A_Use)->setValue(event.onPress); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 584ecb086..ab21bd891 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1113,34 +1113,11 @@ namespace MWWorld return facedObject; } - World::IntersectedObject World::getPointedAtObject() - { - if (MWBase::Environment::get().getWindowManager()->isGuiMode() && - MWBase::Environment::get().getWindowManager()->isConsoleMode()) - { - return getPointedAtObject(getMaxActivationDistance() * 50, false); - } - else - { - auto pointedAtObject = getPointedAtObject(getActivationDistancePlusTelekinesis(), true); - auto ptr = std::get<0>(pointedAtObject); - if (!ptr.isEmpty() && !ptr.getClass().allowTelekinesis(ptr) - && mDistanceToFacedObject > getMaxActivationDistance() && !MWBase::Environment::get().getWindowManager()->isGuiMode()) - return IntersectedObject(); - return pointedAtObject; - } - } - float World::getDistanceToFacedObject() { return mDistanceToFacedObject; } - float World::getDistanceToPointedAtObject() - { - return mDistanceToPointedAtObject; - } - osg::Matrixf World::getActorHeadTransform(const MWWorld::ConstPtr& actor) const { const MWRender::Animation *anim = mRendering->getAnimation(actor); @@ -2051,7 +2028,7 @@ namespace MWWorld const float camDist = mRendering->getCameraDistance(); maxDistance += camDist; MWWorld::Ptr facedObject; - MWRender::RenderingManager::RayResult rayToObject; + MWRender::RayResult rayToObject; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { @@ -2070,45 +2047,6 @@ namespace MWWorld return facedObject; } - World::IntersectedObject World::getPointedAtObject(float maxDistance, bool ignorePlayer) - { - auto sceneRoot = mRendering->getLightRoot(); - - // Find the transform giving the finger's pointing direction. - SceneUtil::FindByNameVisitor findPointerVisitor("Pointer Transform", osg::NodeVisitor::TRAVERSE_ALL_CHILDREN); - sceneRoot->accept(findPointerVisitor); - auto pointerTransform = findPointerVisitor.mFoundNode; - if (pointerTransform) - { - auto pat = pointerTransform->asTransform()->asPositionAttitudeTransform(); - - // Discover the world position of the finger - // (This is actually the base of the last joint bone but so long as it is pointing forward it serves the same purpose). - osg::Matrix worldMatrix = osg::computeLocalToWorld(pointerTransform->getParentalNodePaths()[0]); - pat->computeLocalToWorldMatrix(worldMatrix, nullptr); - osg::Vec3 translate; - osg::Quat rotation; - osg::Vec3 scale; - osg::Quat scaleRotation; - worldMatrix.decompose(translate, rotation, scale, scaleRotation); - osg::Vec3f direction = rotation * osg::Vec3f(-1, 0, 0); - direction.normalize(); - - osg::Vec3f raySource = translate; - osg::Vec3f rayTarget = translate + direction * maxDistance; - - auto rayToObject = mRendering->castRay(raySource, rayTarget, ignorePlayer, false); - if (rayToObject.mHit) - mDistanceToPointedAtObject = (rayToObject.mHitPointWorld - raySource).length(); - 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, rayToObject.mHitPointLocal }; - } - - return IntersectedObject(); - } - bool World::isCellExterior() const { const CellStore *currentCell = mWorldScene->getCurrentCell(); @@ -2255,7 +2193,7 @@ namespace MWWorld { const float maxDist = 200.f; - MWRender::RenderingManager::RayResult result = mRendering->castCameraToViewportRay(cursorX, cursorY, maxDist, true, true); + MWRender::RayResult result = mRendering->castCameraToViewportRay(cursorX, cursorY, maxDist, true, true); CellStore* cell = getPlayerPtr().getCell(); @@ -2282,7 +2220,7 @@ namespace MWWorld bool World::canPlaceObject(float cursorX, float cursorY) { const float maxDist = 200.f; - MWRender::RenderingManager::RayResult result = mRendering->castCameraToViewportRay(cursorX, cursorY, maxDist, true, true); + MWRender::RayResult result = mRendering->castCameraToViewportRay(cursorX, cursorY, maxDist, true, true); if (result.mHit) { @@ -2366,7 +2304,7 @@ namespace MWWorld float len = 1000000.0; - MWRender::RenderingManager::RayResult result = mRendering->castRay(orig, orig+dir*len, true, true); + MWRender::RayResult result = mRendering->castRay(orig, orig+dir*len, true, true); if (result.mHit) pos.pos[2] = result.mHitPointWorld.z(); @@ -3148,7 +3086,7 @@ namespace MWWorld float distance = getMaxActivationDistance(); osg::Vec3f dest = origin + direction * distance; - MWRender::RenderingManager::RayResult result2 = mRendering->castRay(origin, dest, true, true); + MWRender::RayResult result2 = mRendering->castRay(origin, dest, true, true); float dist1 = std::numeric_limits::max(); float dist2 = std::numeric_limits::max(); @@ -3977,4 +3915,122 @@ namespace MWWorld btVector3 hitNormal; return btRayAabb(localFrom, localTo, aabbMin, aabbMax, hitDistance, hitNormal); } + + +#ifdef USE_OPENXR + void World::getPointedAtObject(MWRender::RayResult& result) + { + result = {}; + result.mHit = false; + + if (MWBase::Environment::get().getWindowManager()->isGuiMode() && + MWBase::Environment::get().getWindowManager()->isConsoleMode()) + { + return getPointedAtObject(result, getMaxActivationDistance() * 50, false); + } + else + { + MWRender::RayResult pointedAtObject; + getPointedAtObject(pointedAtObject, getActivationDistancePlusTelekinesis(), true); + auto ptr = pointedAtObject.mHitObject; + if (!ptr.isEmpty() && !ptr.getClass().allowTelekinesis(ptr) + && mDistanceToFacedObject > getMaxActivationDistance() && !MWBase::Environment::get().getWindowManager()->isGuiMode()) + return; + result = pointedAtObject; + } + } + + float World::getDistanceToPointedAtObject() + { + return mDistanceToPointedAtObject; + } + + void World::getPointedAtObject(MWRender::RayResult& result, float maxDistance, bool ignorePlayer) + { + auto sceneRoot = mRendering->getLightRoot(); + result = {}; + result.mHit = false; + + // Find the transform giving the finger's pointing direction. + SceneUtil::FindByNameVisitor findPointerVisitor("Pointer Transform", osg::NodeVisitor::TRAVERSE_ALL_CHILDREN); + sceneRoot->accept(findPointerVisitor); + auto pointerTransform = findPointerVisitor.mFoundNode; + if (pointerTransform) + { + auto pat = pointerTransform->asTransform()->asPositionAttitudeTransform(); + + // Discover the world position of the finger + // (This is actually the base of the last joint bone but so long as it is pointing forward it serves the same purpose). + osg::Matrix worldMatrix = osg::computeLocalToWorld(pointerTransform->getParentalNodePaths()[0]); + pat->computeLocalToWorldMatrix(worldMatrix, nullptr); + osg::Vec3 translate; + osg::Quat rotation; + osg::Vec3 scale; + osg::Quat scaleRotation; + worldMatrix.decompose(translate, rotation, scale, scaleRotation); + osg::Vec3f direction = rotation * osg::Vec3f(-1, 0, 0); + direction.normalize(); + + osg::Vec3f raySource = translate; + osg::Vec3f rayTarget = translate + direction * maxDistance; + + auto rayToObject = mRendering->castRay(raySource, rayTarget, ignorePlayer, false); + if (rayToObject.mHit) + mDistanceToPointedAtObject = (rayToObject.mHitPointWorld - raySource).length(); + else + // Leave a very large but not too large number to permit visualizing a beam going into "infinity" + mDistanceToPointedAtObject = 10000.f; + result = rayToObject; + } + } + + MWWorld::Ptr World::placeObject(const MWWorld::ConstPtr& object, int amount) + { + const float maxDist = 200.f; + + MWRender::RayResult pointedAt; + getPointedAtObject(pointedAt); + + CellStore* cell = getPlayerPtr().getCell(); + + ESM::Position pos = getPlayerPtr().getRefData().getPosition(); + + if (pointedAt.mHit) + { + pos.pos[0] = pointedAt.mHitPointWorld.x(); + pos.pos[1] = pointedAt.mHitPointWorld.y(); + pos.pos[2] = pointedAt.mHitPointWorld.z(); + } + // We want only the Z part of the player's rotation + // TODO: Use the hand's orientation? + pos.rot[0] = 0; + pos.rot[1] = 0; + + // copy the object and set its count + Ptr dropped = copyObjectToCell(object, cell, pos, amount, true); + + // only the player place items in the world, so no need to check actor + PCDropped(dropped); + + return dropped; + } + + bool World::canPlaceObject() + { + const float maxDist = 200.f; + MWRender::RayResult pointedAt; + getPointedAtObject(pointedAt); + + if (pointedAt.mHit) + { + // check if the wanted position is on a flat surface, and not e.g. against a vertical wall + if (std::acos((pointedAt.mHitNormalWorld / pointedAt.mHitNormalWorld.length()) * osg::Vec3f(0, 0, 1)) >= osg::DegreesToRadians(30.f)) + return false; + + return true; + } + else + return false; + } +#endif } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 54fedb904..2553c1958 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -140,8 +140,6 @@ namespace MWWorld MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer=true); - IntersectedObject getPointedAtObject(float maxDistance, bool ignorePlayer=true); - public: // FIXME void addContainerScripts(const Ptr& reference, CellStore* cell) override; void removeContainerScripts(const Ptr& reference) override; @@ -176,7 +174,6 @@ namespace MWWorld float mSwimHeightScale; float mDistanceToFacedObject; - float mDistanceToPointedAtObject; bool mTeleportEnabled; bool mLevitationEnabled; @@ -377,11 +374,7 @@ namespace MWWorld MWWorld::Ptr getFacedObject() override; ///< Return pointer to the object the player is looking at, if it is within activation range - IntersectedObject getPointedAtObject() override; - ///< Return pointer to the object and/or node the player is currently pointing at - float getDistanceToFacedObject() override; - float getDistanceToPointedAtObject() override; /// Returns a pointer to the object the provided object would hit (if within the /// specified distance), and the point where the hit occurs. This will attempt to @@ -735,6 +728,25 @@ namespace MWWorld osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const override; bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const override; + +#ifdef USE_OPENXR + private: + float mDistanceToPointedAtObject; + void getPointedAtObject(MWRender::RayResult& result, float maxDistance, bool ignorePlayer = true); + public: + void getPointedAtObject(MWRender::RayResult& result) override; + ///< Return pointer to the object and/or node the player is currently pointing at + float getDistanceToPointedAtObject() override; + ///< Return the distance to the object and/or node the player is currently pointing at + + MWWorld::Ptr placeObject(const MWWorld::ConstPtr& object, int amount) override; + ///< copy and place an object into the gameworld where the player is currently pointing + /// @param object + /// @param number of objects to place + + bool canPlaceObject() override; + ///< @return true if it is possible to place on object where the player is currently pointing +#endif }; }