diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 635e9481b..6f8434535 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -17,6 +17,8 @@ ToolTips::ToolTips(WindowManager* windowManager) : , mWindowManager(windowManager) , mFullHelp(false) , mEnabled(true) + , mFocusToolTipX(0.0) + , mFocusToolTipY(0.0) { getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); @@ -118,11 +120,8 @@ void ToolTips::onFrame(float frameDuration) { IntSize tooltipSize = getToolTipViaPtr(); - // adjust tooltip size to fit its content, position it above the crosshair - /// \todo Slide the tooltip along the bounding box of the focused object (like in Morrowind) - /// relevant link: http://www.ogre3d.org/tikiwiki/ObjectTextDisplay - setCoord(std::max(0, viewSize.width/2 - (tooltipSize.width)/2), - std::max(0, viewSize.height/2 - (tooltipSize.height) - 32), + setCoord(viewSize.width/2 - tooltipSize.width/2, + std::max(0, int(mFocusToolTipY*viewSize.height - tooltipSize.height)), tooltipSize.width, tooltipSize.height); } @@ -387,3 +386,9 @@ bool ToolTips::getFullHelp() const { return mFullHelp; } + +void ToolTips::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) +{ + mFocusToolTipX = (min_x + max_x) / 2; + mFocusToolTipY = min_y; +} diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 87b9e97bf..4be0baff9 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -45,6 +45,8 @@ namespace MWGui bool getFullHelp() const; void setFocusObject(const MWWorld::Ptr& focus); + void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); + ///< set the screen-space position of the tooltip for focused object static std::string getValueString(const int value, const std::string& prefix); ///< @return "prefix: value" or "" if value is 0 @@ -73,6 +75,9 @@ namespace MWGui MyGUI::IntSize createToolTip(const ToolTipInfo& info); ///< @return requested tooltip size + float mFocusToolTipX; + float mFocusToolTipY; + bool mGameMode; bool mEnabled; diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index bb533e698..c93d5303c 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -540,6 +540,11 @@ void WindowManager::setFocusObject(const MWWorld::Ptr& focus) mToolTips->setFocusObject(focus); } +void WindowManager::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) +{ + mToolTips->setFocusObjectScreenCoords(min_x, min_y, max_x, max_y); +} + void WindowManager::toggleFullHelp() { mToolTips->toggleFullHelp(); diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 5dfcf6470..cff93266c 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -165,6 +165,7 @@ namespace MWGui void setPlayerDir(const float x, const float y); ///< set player view direction in map space void setFocusObject(const MWWorld::Ptr& focus); + void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); void setMouseVisible(bool visible); void setDragDrop(bool dragDrop); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a95a179c6..f795ed372 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -518,4 +518,43 @@ void RenderingManager::switchToExterior() mRendering.getScene()->setCameraRelativeRendering(true); } +Ogre::Vector4 RenderingManager::boundingBoxToScreen(Ogre::AxisAlignedBox bounds) +{ + Ogre::Matrix4 mat = mRendering.getCamera()->getViewMatrix(); + + const Ogre::Vector3* corners = bounds.getAllCorners(); + + float min_x = 1.0f, max_x = 0.0f, min_y = 1.0f, max_y = 0.0f; + + // expand the screen-space bounding-box so that it completely encloses + // the object's AABB + for (int i=0; i<8; i++) + { + Ogre::Vector3 corner = corners[i]; + + // multiply the AABB corner vertex by the view matrix to + // get a camera-space vertex + corner = mat * corner; + + // make 2D relative/normalized coords from the view-space vertex + // by dividing out the Z (depth) factor -- this is an approximation + float x = corner.x / corner.z + 0.5; + float y = corner.y / corner.z + 0.5; + + if (x < min_x) + min_x = x; + + if (x > max_x) + max_x = x; + + if (y < min_y) + min_y = y; + + if (y > max_y) + max_y = y; + } + + return Vector4(min_x, min_y, max_x, max_y); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 0d11b3d57..8b457997d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -151,6 +151,10 @@ class RenderingManager: private RenderingInterface { ///< Skip the animation for the given MW-reference for one frame. Calls to this function for /// references that are currently not in the rendered scene should be ignored. + Ogre::Vector4 boundingBoxToScreen(Ogre::AxisAlignedBox bounds); + ///< transform the specified bounding box (in world coordinates) into screen coordinates. + /// @return packed vector4 (min_x, min_y, max_x, max_y) + private: void setAmbientMode(); diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index d2b687742..0474d894c 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -768,7 +768,24 @@ namespace MWWorld // inform the GUI about focused object try { - MWBase::Environment::get().getWindowManager()->setFocusObject(getPtrViaHandle(mFacedHandle)); + MWWorld::Ptr object = getPtrViaHandle(mFacedHandle); + MWBase::Environment::get().getWindowManager()->setFocusObject(object); + + // retrieve object dimensions so we know where to place the floating label + Ogre::SceneNode* node = object.getRefData().getBaseNode(); + Ogre::AxisAlignedBox bounds; + int i; + for (i=0; inumAttachedObjects(); ++i) + { + Ogre::MovableObject* ob = node->getAttachedObject(i); + bounds.merge(ob->getWorldBoundingBox()); + } + if (bounds.isFinite()) + { + Vector4 screenCoords = mRendering->boundingBoxToScreen(bounds); + MWBase::Environment::get().getWindowManager()->setFocusObjectScreenCoords( + screenCoords[0], screenCoords[1], screenCoords[2], screenCoords[3]); + } } catch (std::runtime_error&) {