From efdea0fb4272a033ba5aadbd0e2c2528cdc48e99 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sun, 22 Dec 2024 04:52:10 +0300 Subject: [PATCH] Stick focused object tooltip to slightly above its top (#4710) --- CHANGELOG.md | 1 + apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 12 +++---- apps/openmw/mwgui/tooltips.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +-- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 38 +++++++++-------------- apps/openmw/mwrender/renderingmanager.hpp | 5 ++- apps/openmw/mwworld/worldimp.cpp | 7 ++--- 9 files changed, 31 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bc4e3821d..84bd44bd18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Bug #4508: Can't stack enchantment buffs from different instances of the same self-cast generic magic apparel Bug #4610: Casting a Bound Weapon spell cancels the casting animation by equipping the weapon prematurely Bug #4683: Disposition decrease when player commits crime is not implemented properly + Bug #4710: Object tooltips don't always stick to the top of the object Bug #4742: Actors with wander never stop walking after Loopgroup Walkforward Bug #4743: PlayGroup doesn't play non-looping animations correctly Bug #4754: Stack of ammunition cannot be equipped partially diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 0b2e85f3e1..df334bbfe8 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -184,7 +184,7 @@ namespace MWBase ///< change the active cell virtual void setFocusObject(const MWWorld::Ptr& focus) = 0; - virtual void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) = 0; + virtual void setFocusObjectScreenCoords(float x, float y) = 0; virtual void setCursorVisible(bool visible) = 0; virtual void setCursorActive(bool active) = 0; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 960a4a5a21..28f0b80010 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -308,9 +308,9 @@ namespace MWGui { MyGUI::IntSize tooltipSize = getToolTipViaPtr(mFocusObject.getCellRef().getCount(), true, checkOwned()); - setCoord(viewSize.width / 2 - tooltipSize.width / 2, - std::max(0, int(mFocusToolTipY * viewSize.height - tooltipSize.height)), tooltipSize.width, - tooltipSize.height); + const int left = viewSize.width / 2 - tooltipSize.width / 2; + const int top = std::max(0, int(mFocusToolTipY * viewSize.height - tooltipSize.height - 20)); + setCoord(left, top, tooltipSize.width, tooltipSize.height); mDynamicToolTipBox->setVisible(true); } @@ -818,10 +818,10 @@ namespace MWGui return mFullHelp; } - void ToolTips::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) + void ToolTips::setFocusObjectScreenCoords(float x, float y) { - mFocusToolTipX = (min_x + max_x) / 2; - mFocusToolTipY = min_y; + mFocusToolTipX = x; + mFocusToolTipY = y; } void ToolTips::createSkillToolTip(MyGUI::Widget* widget, ESM::RefId skillId) diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 132698475f..2c817c3bde 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -64,7 +64,7 @@ namespace MWGui void clear(); void setFocusObject(const MWWorld::Ptr& focus); - void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); + void setFocusObjectScreenCoords(float x, float y); ///< set the screen-space position of the tooltip for focused object static std::string getWeightString(const float weight, const std::string& prefix); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1816cf8a61..e51350d19f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1038,9 +1038,9 @@ namespace MWGui } } - void WindowManager::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) + void WindowManager::setFocusObjectScreenCoords(float x, float y) { - mToolTips->setFocusObjectScreenCoords(min_x, min_y, max_x, max_y); + mToolTips->setFocusObjectScreenCoords(x, y); } bool WindowManager::toggleFullHelp() diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3ca863127b..052a269188 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -204,7 +204,7 @@ namespace MWGui void changeCell(const MWWorld::CellStore* cell) override; ///< change the active cell void setFocusObject(const MWWorld::Ptr& focus) override; - void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) override; + void setFocusObjectScreenCoords(float x, float y) override; void getMousePosition(int& x, int& y) override; void getMousePosition(float& x, float& y) override; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index fcb2d18e4c..afb6101534 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1013,34 +1013,24 @@ namespace MWRender mScreenshotManager->screenshot(image, w, h); } - osg::Vec4f RenderingManager::getScreenBounds(const osg::BoundingBox& worldbb) + osg::Vec2f RenderingManager::getScreenCoords(const osg::BoundingBox& bb) { - if (!worldbb.valid()) - return osg::Vec4f(); - osg::Matrix viewProj = mViewer->getCamera()->getViewMatrix() * mViewer->getCamera()->getProjectionMatrix(); - float min_x = 1.0f, max_x = 0.0f, min_y = 1.0f, max_y = 0.0f; - for (int i = 0; i < 8; ++i) + if (bb.valid()) { - osg::Vec3f corner = worldbb.corner(i); - corner = corner * viewProj; - - float x = (corner.x() + 1.f) * 0.5f; - float y = (corner.y() - 1.f) * (-0.5f); - - 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; + const osg::Matrix viewProj + = mViewer->getCamera()->getViewMatrix() * mViewer->getCamera()->getProjectionMatrix(); + const osg::Vec3f worldPoint((bb.xMin() + bb.xMax()) * 0.5f, (bb.yMin() + bb.yMax()) * 0.5f, bb.zMax()); + const osg::Vec4f clipPoint = osg::Vec4f(worldPoint, 1.0f) * viewProj; + if (clipPoint.w() > 0.f) + { + const float screenPointX = (clipPoint.x() / clipPoint.w() + 1.f) * 0.5f; + const float screenPointY = (clipPoint.y() / clipPoint.w() - 1.f) * (-0.5f); + if (screenPointX >= 0.f && screenPointX <= 1.f && screenPointY >= 0.f && screenPointY <= 1.f) + return osg::Vec2f(screenPointX, screenPointY); + } } - return osg::Vec4f(min_x, min_y, max_x, max_y); + return osg::Vec2f(0.5f, 0.f); } RenderingManager::RayResult getIntersectionResult(osgUtil::LineSegmentIntersector* intersector, diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 7e68f666a1..ee587f84cc 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -185,9 +185,8 @@ namespace MWRender RayResult castCameraToViewportRay( const float nX, const float nY, float maxDistance, bool ignorePlayer, bool ignoreActors = false); - /// Get the bounding box of the given object in screen coordinates as (minX, minY, maxX, maxY), with (0,0) being - /// the top left corner. - osg::Vec4f getScreenBounds(const osg::BoundingBox& worldbb); + /// Get normalized screen coordinates of the bounding box's summit, where (0,0) is the top left corner + osg::Vec2f getScreenCoords(const osg::BoundingBox& bb); void setSkyEnabled(bool enabled); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index bacedcab33..2ec62c4543 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1784,7 +1784,7 @@ namespace MWWorld // inform the GUI about focused object MWWorld::Ptr object = getFacedObject(); - // retrieve object dimensions so we know where to place the floating label + // retrieve the object's top point's screen position so we know where to place the floating label if (!object.isEmpty()) { osg::BoundingBox bb = mPhysics->getBoundingBox(object); @@ -1795,9 +1795,8 @@ namespace MWWorld object.getRefData().getBaseNode()->accept(computeBoundsVisitor); bb = computeBoundsVisitor.getBoundingBox(); } - osg::Vec4f screenBounds = mRendering->getScreenBounds(bb); - MWBase::Environment::get().getWindowManager()->setFocusObjectScreenCoords( - screenBounds.x(), screenBounds.y(), screenBounds.z(), screenBounds.w()); + const osg::Vec2f pos = mRendering->getScreenCoords(bb); + MWBase::Environment::get().getWindowManager()->setFocusObjectScreenCoords(pos.x(), pos.y()); } MWBase::Environment::get().getWindowManager()->setFocusObject(object);