diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 3d981a9c7b..cb53105a79 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -103,6 +104,8 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr) osg::ref_ptr insert (new osg::PositionAttitudeTransform); cellnode->addChild(insert); + insert->getOrCreateUserDataContainer()->addUserObject(new PtrHolder(ptr)); + const float *f = ptr.getRefData().getPosition().pos; insert->setPosition(osg::Vec3(f[0], f[1], f[2])); @@ -216,6 +219,14 @@ void Objects::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) osg::Node* objectNode = cur.getRefData().getBaseNode(); + osg::UserDataContainer* userDataContainer = objectNode->getUserDataContainer(); + if (userDataContainer) + for (unsigned int i=0; igetNumUserObjects(); ++i) + { + if (dynamic_cast(userDataContainer->getUserObject(i))) + userDataContainer->setUserObject(i, new PtrHolder(cur)); + } + if (objectNode->getNumParents()) objectNode->getParent(0)->removeChild(objectNode); cellnode->addChild(objectNode); diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 716192959d..b3799d0efb 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -6,6 +6,9 @@ #include #include +#include + +#include "../mwworld/ptr.hpp" namespace osg { @@ -24,7 +27,6 @@ namespace Resource namespace MWWorld { - class Ptr; class CellStore; } @@ -32,6 +34,27 @@ namespace MWRender{ class Animation; +class PtrHolder : public osg::Object +{ +public: + PtrHolder(MWWorld::Ptr ptr) + : mPtr(ptr) + { + } + + PtrHolder() + { + } + + PtrHolder(const PtrHolder& copy, const osg::CopyOp& copyop) + : mPtr(copy.mPtr) + { + } + + META_Object(MWRender, PtrHolder) + + MWWorld::Ptr mPtr; +}; class Objects{ typedef std::map PtrAnimationMap; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b8620d60b0..c49a444939 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -8,7 +8,10 @@ #include #include #include +#include +#include +#include #include #include @@ -292,6 +295,84 @@ namespace MWRender mObjects->removeObject(ptr); } + osg::Vec4f RenderingManager::getScreenBounds(const MWWorld::Ptr& ptr) + { + if (!ptr.getRefData().getBaseNode()) + return osg::Vec4f(); + + osg::ComputeBoundsVisitor computeBoundsVisitor; + ptr.getRefData().getBaseNode()->accept(computeBoundsVisitor); + + 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) + { + osg::Vec3f corner = computeBoundsVisitor.getBoundingBox().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; + } + + return osg::Vec4f(min_x, min_y, max_x, max_y); + } + + MWWorld::Ptr RenderingManager::getFacedObject(const float nX, const float nY, float maxDistance, bool ignorePlayer) + { + osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::PROJECTION, + nX * 2.f - 1.f, nY * (-2.f) + 1.f)); + + osg::Vec3d dist (0.f, 0.f, -maxDistance); + + dist = dist * mViewer->getCamera()->getProjectionMatrix(); + + osg::Vec3d end = intersector->getEnd(); + end.z() = dist.z(); + intersector->setEnd(end); + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); + + osgUtil::IntersectionVisitor intersectionVisitor(intersector); + if (ignorePlayer) + intersectionVisitor.setTraversalMask(intersectionVisitor.getTraversalMask() & (~Mask_Player)); + + mViewer->getCamera()->accept(intersectionVisitor); + + if (intersector->containsIntersections()) + { + osgUtil::LineSegmentIntersector::Intersection intersection = intersector->getFirstIntersection(); + + PtrHolder* ptrHolder = NULL; + for (osg::NodePath::const_iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) + { + osg::UserDataContainer* userDataContainer = (*it)->getUserDataContainer(); + if (!userDataContainer) + continue; + for (unsigned int i=0; igetNumUserObjects(); ++i) + { + if (PtrHolder* p = dynamic_cast(userDataContainer->getUserObject(i))) + ptrHolder = p; + } + } + + if (ptrHolder) + return ptrHolder->mPtr; + } + + return MWWorld::Ptr(); + } + void RenderingManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) { mObjects->updatePtr(old, updated); @@ -332,6 +413,7 @@ namespace MWRender if (!mPlayerNode) { mPlayerNode = new osg::PositionAttitudeTransform; + mPlayerNode->setNodeMask(Mask_Player); mLightRoot->addChild(mPlayerNode); } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 2978c99835..011ceee09d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -73,6 +73,13 @@ namespace MWRender void removeObject(const MWWorld::Ptr& ptr); + /// Return the object under the mouse cursor / crosshair position, given by nX and nY normalized screen coordinates, + /// where (0,0) is the top left corner. + MWWorld::Ptr getFacedObject(const float nX, const float nY, float maxDistance, bool ignorePlayer); + + /// 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 MWWorld::Ptr& ptr); + void setSkyEnabled(bool enabled); bool toggleRenderMode(RenderMode mode); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 512f9f4ad6..7382438d17 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -10,13 +10,14 @@ namespace MWRender Mask_UpdateVisitor = 0x1, // reserved for separating UpdateVisitors from CullVisitors // child of Scene - Mask_Effect = 0x2, - Mask_Debug = 0x4, - Mask_Actor = 0x8, + Mask_Effect = (1<<1), + Mask_Debug = (1<<2), + Mask_Actor = (1<<3), + Mask_Player = (1<<4), // top level masks - Mask_Scene = 0x10, - Mask_GUI = 0x20 + Mask_Scene = (1<<5), + Mask_GUI = (1<<6) }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 442f493c13..5689b12cc0 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1031,11 +1031,11 @@ namespace MWWorld MWWorld::Ptr World::getFacedObject() { - std::string facedHandle; + MWWorld::Ptr facedObject; if (MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager()->isConsoleMode()) - getFacedHandle(facedHandle, getMaxActivationDistance() * 50, false); + facedObject = getFacedObject(getMaxActivationDistance() * 50, false); else { float telekinesisRangeBonus = @@ -1045,13 +1045,10 @@ namespace MWWorld float activationDistance = getMaxActivationDistance() + telekinesisRangeBonus; - getFacedHandle(facedHandle, activationDistance); + facedObject = getFacedObject(activationDistance); } - //if (facedHandle.empty()) - return MWWorld::Ptr(); - - //return getPtrViaHandle(facedHandle); + return facedObject; } std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) @@ -1593,11 +1590,8 @@ namespace MWWorld mWorldScene->update (duration, paused); - /* - performUpdateSceneQueries (); - updateWindowManager (); - */ + updateSoundListener(); /* if (!paused && mPlayer->getPlayer().getCell()->isExterior()) @@ -1648,57 +1642,27 @@ namespace MWWorld // retrieve object dimensions so we know where to place the floating label if (!object.isEmpty ()) { - Ogre::SceneNode* node = object.getRefData().getBaseNodeOld(); - Ogre::AxisAlignedBox bounds = node->_getWorldAABB(); - if (bounds.isFinite()) - { - Ogre::Vector4 screenCoords;// = mRendering->boundingBoxToScreen(bounds); - MWBase::Environment::get().getWindowManager()->setFocusObjectScreenCoords( - screenCoords[0], screenCoords[1], screenCoords[2], screenCoords[3]); - } + osg::Vec4f screenBounds = mRendering->getScreenBounds(object); + + MWBase::Environment::get().getWindowManager()->setFocusObjectScreenCoords( + screenBounds.x(), screenBounds.y(), screenBounds.z(), screenBounds.w()); } } - void World::performUpdateSceneQueries () + MWWorld::Ptr World::getFacedObject(float maxDistance, bool ignorePlayer) { -#if 0 - if (!mRendering->occlusionQuerySupported()) - { - // cast a ray from player to sun to detect if the sun is visible - // this is temporary until we find a better place to put this code - // currently its here because we need to access the physics system - const float* p = mPlayer->getPlayer().getRefData().getPosition().pos; - Vector3 sun = mRendering->getSkyManager()->getRealSunPos(); - mRendering->getSkyManager()->setGlare(!mPhysics->castRay(Ogre::Vector3(p[0], p[1], p[2]), sun)); - } -#endif - } + maxDistance += mRendering->getCameraDistance(); - void World::getFacedHandle(std::string& facedHandle, float maxDistance, bool ignorePlayer) - { - //maxDistance += mRendering->getCameraDistance(); - - std::vector < std::pair < float, std::string > > results; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { float x, y; MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); - //results = mPhysics->getFacedHandles(x, y, maxDistance); + return mRendering->getFacedObject(x, y, maxDistance, ignorePlayer); } else { - //results = mPhysics->getFacedHandles(maxDistance); + return mRendering->getFacedObject(0.5f, 0.5f, maxDistance, ignorePlayer); } - - if (ignorePlayer && - !results.empty() && results.front().second == "player") - results.erase(results.begin()); - - if (results.empty() - || results.front().second.find("HeightField") != std::string::npos) // Blocked by terrain - facedHandle = ""; - else - facedHandle = results.front().second; } bool World::isCellExterior() const @@ -2744,10 +2708,7 @@ namespace MWWorld if (actor == getPlayerPtr()) { // For the player, use camera to aim - std::string facedHandle; - getFacedHandle(facedHandle, distance); - //if (!facedHandle.empty()) - // target = getPtrViaHandle(facedHandle); + target = getFacedObject(distance); } else { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index af1e68af1b..e217f4bc4e 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -121,8 +121,7 @@ namespace MWWorld void updateSoundListener(); void updateWindowManager (); - void performUpdateSceneQueries (); - void getFacedHandle(std::string& facedHandle, float maxDistance, bool ignorePlayer=true); + MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer=true); void removeContainerScripts(const Ptr& reference); void addContainerScripts(const Ptr& reference, CellStore* cell);