mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-30 12:06:48 +00:00
Drop items at location
This commit is contained in:
parent
08c08646cd
commit
31f5b76394
11 changed files with 286 additions and 113 deletions
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -270,6 +270,7 @@ namespace MWGui
|
|||
}
|
||||
}
|
||||
|
||||
// XR-TODO: Implement equivalent
|
||||
void HUD::onWorldMouseOver(MyGUI::Widget* _sender, int x, int y)
|
||||
{
|
||||
if (mDragAndDrop->mIsOnDragAndDrop)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<osgUtil::LineSegmentIntersector> 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<osgUtil::LineSegmentIntersector> intersector (new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::PROJECTION,
|
||||
nX * 2.f - 1.f, nY * (-2.f) + 1.f));
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<float>::max();
|
||||
float dist2 = std::numeric_limits<float>::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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue