Implement getFacedObject using osgUtil::IntersectionVisitor

c++11
scrawl 10 years ago
parent c2131e7c31
commit 8b322fcd06

@ -6,6 +6,7 @@
#include <osg/Group>
#include <osg/Geode>
#include <osg/PositionAttitudeTransform>
#include <osg/UserDataContainer>
#include <osgUtil/IncrementalCompileOperation>
@ -103,6 +104,8 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr)
osg::ref_ptr<osg::PositionAttitudeTransform> 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; i<userDataContainer->getNumUserObjects(); ++i)
{
if (dynamic_cast<PtrHolder*>(userDataContainer->getUserObject(i)))
userDataContainer->setUserObject(i, new PtrHolder(cur));
}
if (objectNode->getNumParents())
objectNode->getParent(0)->removeChild(objectNode);
cellnode->addChild(objectNode);

@ -6,6 +6,9 @@
#include <string>
#include <osg/ref_ptr>
#include <osg/Object>
#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<MWWorld::Ptr,Animation*> PtrAnimationMap;

@ -8,7 +8,10 @@
#include <osg/Fog>
#include <osg/Group>
#include <osg/PositionAttitudeTransform>
#include <osg/UserDataContainer>
#include <osg/ComputeBoundsVisitor>
#include <osgUtil/LineSegmentIntersector>
#include <osgUtil/IncrementalCompileOperation>
#include <osgViewer/Viewer>
@ -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<osgUtil::LineSegmentIntersector> 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; i<userDataContainer->getNumUserObjects(); ++i)
{
if (PtrHolder* p = dynamic_cast<PtrHolder*>(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);
}

@ -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);

@ -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)
};
}

@ -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<MWWorld::Ptr,osg::Vec3f> 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);
void World::performUpdateSceneQueries ()
{
#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));
MWBase::Environment::get().getWindowManager()->setFocusObjectScreenCoords(
screenBounds.x(), screenBounds.y(), screenBounds.z(), screenBounds.w());
}
#endif
}
void World::getFacedHandle(std::string& facedHandle, float maxDistance, bool ignorePlayer)
MWWorld::Ptr World::getFacedObject(float maxDistance, bool ignorePlayer)
{
//maxDistance += mRendering->getCameraDistance();
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
{

@ -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);

Loading…
Cancel
Save