diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index d926346d3..bab0051b8 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -244,7 +244,7 @@ void ContainerBase::Update() if(mDragAndDrop->mIsOnDragAndDrop) { if(mDragAndDrop->mDraggedWidget) - mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition() - MyGUI::IntPoint(21, 21)); + mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); else mDragAndDrop->mIsOnDragAndDrop = false; //If this happens, there is a bug. } } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 482047b9b..b99276440 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -91,6 +91,7 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) LocalMapBase::init(minimap, this); mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); + mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver); } void HUD::setFpsLevel(int level) @@ -261,16 +262,19 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) // drop item into the gameworld MWWorld::Ptr object = *mDragAndDrop->mStore.begin(); - float* playerPos; - playerPos = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getRefData().getPosition().pos; - MWWorld::Ptr::CellStore* cell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); /// \todo this might be a different cell + MWWorld::World* world = MWBase::Environment::get().getWorld(); - ESM::Position& pos = object.getRefData().getPosition(); - pos.pos[0] = playerPos[0]; - pos.pos[1] = playerPos[1]; - pos.pos[2] = playerPos[2]; + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); + float mouseX = cursorPosition.left / float(viewSize.width); + float mouseY = cursorPosition.top / float(viewSize.height); - MWBase::Environment::get().getWorld()->insertObject(object, cell); + if (world->canPlaceObject(mouseX, mouseY)) + world->placeObject(object, mouseX, mouseY); + else + world->dropObjectOnGround(object); + + MyGUI::PointerManager::getInstance().setPointer("arrow"); std::string sound = MWWorld::Class::get(object).getDownSoundId(object); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); @@ -284,3 +288,30 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) } } +void HUD::onWorldMouseOver(MyGUI::Widget* _sender, int x, int y) +{ + if (mDragAndDrop->mIsOnDragAndDrop) + { + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); + float mouseX = cursorPosition.left / float(viewSize.width); + float mouseY = cursorPosition.top / float(viewSize.height); + + MWWorld::World* world = MWBase::Environment::get().getWorld(); + + // if we can't drop the object at the wanted position, show the "drop on ground" cursor. + bool canDrop = world->canPlaceObject(mouseX, mouseY); + + if (!canDrop) + MyGUI::PointerManager::getInstance().setPointer("drop_ground"); + else + MyGUI::PointerManager::getInstance().setPointer("arrow"); + + } + else + { + MyGUI::PointerManager::getInstance().setPointer("arrow"); + /// \todo make it possible to pick up objects with the mouse, if inventory or container window is open + } +} + diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 22b1b8738..cccfb0541 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -52,5 +52,6 @@ namespace MWGui DragAndDrop* mDragAndDrop; void onWorldClicked(MyGUI::Widget* _sender); + void onWorldMouseOver(MyGUI::Widget* _sender, int x, int y); }; } diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 8624699cd..a4788ad3b 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -576,5 +576,4 @@ void WindowManager::setDragDrop(bool dragDrop) { mToolTips->setEnabled(!dragDrop); MWBase::Environment::get().getInputManager()->setDragDrop(dragDrop); - setMouseVisible(!dragDrop); } diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index fb13e37c6..808c712a0 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -80,7 +80,7 @@ namespace MWWorld Ray centerRay = mRender.getCamera()->getCameraToViewportRay( mRender.getViewport()->getWidth()/2, mRender.getViewport()->getHeight()/2); - btVector3 result(centerRay.getPoint(500*extent).x,-centerRay.getPoint(500*extent).z,centerRay.getPoint(500*extent).y); + btVector3 result(centerRay.getPoint(500*extent).x,-centerRay.getPoint(500*extent).z,centerRay.getPoint(500*extent).y); /// \todo make this distance (ray length) configurable return result; } @@ -95,6 +95,29 @@ namespace MWWorld return !(result.first == ""); } + std::pair PhysicsSystem::castRay(float mouseX, float mouseY) + { + Ogre::Ray ray = mRender.getCamera()->getCameraToViewportRay( + mouseX, + mouseY); + Ogre::Vector3 from = ray.getOrigin(); + Ogre::Vector3 to = ray.getPoint(200); /// \todo make this distance (ray length) configurable + + btVector3 _from, _to; + // OGRE to MW coordinates + _from = btVector3(from.x, -from.z, from.y); + _to = btVector3(to.x, -to.z, to.y); + + std::pair result = mEngine->rayTest(_from, _to); + + if (result.first == "") + return std::make_pair(false, Ogre::Vector3()); + else + { + return std::make_pair(true, ray.getPoint(200*result.second)); /// \todo make this distance (ray length) configurable + } + } + void PhysicsSystem::doPhysics(float dt, const std::vector >& actors) { //set the DebugRenderingMode. To disable it,set it to 0 diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 1af6bcca2..9b03d2124 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -53,6 +53,9 @@ namespace MWWorld // cast ray, return true if it hit something bool castRay(const Ogre::Vector3& from, const Ogre::Vector3& to); + std::pair castRay(float mouseX, float mouseY); + ///< cast ray from the mouse, return true if it hit something and the first result (in OGRE coordinates) + void insertObjectPhysics(const MWWorld::Ptr& ptr, std::string model); void insertActorPhysics(const MWWorld::Ptr&, std::string model); diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 0474d894c..973407b0c 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -965,9 +965,57 @@ namespace MWWorld mRendering->toggleWater(); } - void World::insertObject(MWWorld::Ptr ptr, Ptr::CellStore* cell) + bool World::placeObject(MWWorld::Ptr object, float cursorX, float cursorY) { - mWorldScene->insertObject(ptr, cell); + std::pair result = mPhysics->castRay(cursorX, cursorY); + + if (!result.first) + return false; + + MWWorld::Ptr::CellStore* cell; + if (isCellExterior()) + { + int cellX, cellY; + positionToIndex(result.second[0], -result.second[2], cellX, cellY); + cell = mCells.getExterior(cellX, cellY); + } + else + cell = getPlayer().getPlayer().getCell(); + + ESM::Position& pos = object.getRefData().getPosition(); + pos.pos[0] = result.second[0]; + pos.pos[1] = -result.second[2]; + pos.pos[2] = result.second[1]; + + mWorldScene->insertObject(object, cell); + + /// \todo retrieve the bounds of the object and translate it accordingly + + return true; } + bool World::canPlaceObject(float cursorX, float cursorY) + { + std::pair result = mPhysics->castRay(cursorX, cursorY); + + /// \todo also check if the wanted position is on a flat surface, and not e.g. against a vertical wall! + + if (!result.first) + return false; + return true; + } + + void World::dropObjectOnGround(MWWorld::Ptr object) + { + MWWorld::Ptr::CellStore* cell = getPlayer().getPlayer().getCell(); + + float* playerPos = getPlayer().getPlayer().getRefData().getPosition().pos; + + ESM::Position& pos = object.getRefData().getPosition(); + pos.pos[0] = playerPos[0]; + pos.pos[1] = playerPos[1]; + pos.pos[2] = playerPos[2]; + + mWorldScene->insertObject(object, cell); + } } diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 3b56dea97..1ed6a976e 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -263,9 +263,17 @@ namespace MWWorld void update (float duration); - void insertObject (MWWorld::Ptr ptr, Ptr::CellStore* cell); - ///< insert object in a given cell - /// \note this method is only meant for dropping items into the gameworld from a container + bool placeObject(MWWorld::Ptr object, float cursorX, float cursorY); + ///< place an object into the gameworld at the specified cursor position + /// @param object + /// @param cursor X (relative 0-1) + /// @param cursor Y (relative 0-1) + /// @return true if the object was placed, or false if it was rejected because the position is too far away + + void dropObjectOnGround(MWWorld::Ptr object); + + bool canPlaceObject(float cursorX, float cursorY); + ///< @return true if it is possible to place on object at specified cursor location }; } diff --git a/files/mygui/openmw.pointer.xml b/files/mygui/openmw.pointer.xml index 0fbef2fdf..42ee5d435 100644 --- a/files/mygui/openmw.pointer.xml +++ b/files/mygui/openmw.pointer.xml @@ -26,4 +26,9 @@ + + + + + diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index 81cd99fea..a5044fb78 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -8,7 +8,6 @@ + - - diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index b2bd90d10..4c509ae13 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -36,6 +36,13 @@ + + + + + + +