|
|
|
@ -59,6 +59,7 @@
|
|
|
|
|
#include "../mwworld/cellstore.hpp"
|
|
|
|
|
#include "../mwworld/class.hpp"
|
|
|
|
|
#include "../mwworld/groundcoverstore.hpp"
|
|
|
|
|
#include "../mwworld/scene.hpp"
|
|
|
|
|
|
|
|
|
|
#include "../mwgui/postprocessorhud.hpp"
|
|
|
|
|
|
|
|
|
@ -1014,20 +1015,17 @@ namespace MWRender
|
|
|
|
|
return osg::Vec4f(min_x, min_y, max_x, max_y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RenderingManager::RayResult getIntersectionResult(osgUtil::LineSegmentIntersector* intersector)
|
|
|
|
|
RenderingManager::RayResult getIntersectionResult(osgUtil::LineSegmentIntersector* intersector,
|
|
|
|
|
const osg::ref_ptr<osgUtil::IntersectionVisitor>& visitor, std::span<const MWWorld::Ptr> ignoreList = {})
|
|
|
|
|
{
|
|
|
|
|
RenderingManager::RayResult result;
|
|
|
|
|
result.mHit = false;
|
|
|
|
|
result.mRatio = 0;
|
|
|
|
|
if (intersector->containsIntersections())
|
|
|
|
|
{
|
|
|
|
|
result.mHit = true;
|
|
|
|
|
osgUtil::LineSegmentIntersector::Intersection intersection = intersector->getFirstIntersection();
|
|
|
|
|
|
|
|
|
|
result.mHitPointWorld = intersection.getWorldIntersectPoint();
|
|
|
|
|
result.mHitNormalWorld = intersection.getWorldIntersectNormal();
|
|
|
|
|
result.mRatio = intersection.ratio;
|
|
|
|
|
if (!intersector->containsIntersections())
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
auto test = [&](const osgUtil::LineSegmentIntersector::Intersection& intersection) {
|
|
|
|
|
PtrHolder* ptrHolder = nullptr;
|
|
|
|
|
std::vector<RefnumMarker*> refnumMarkers;
|
|
|
|
|
for (osg::NodePath::const_iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end();
|
|
|
|
@ -1039,9 +1037,16 @@ namespace MWRender
|
|
|
|
|
for (unsigned int i = 0; i < userDataContainer->getNumUserObjects(); ++i)
|
|
|
|
|
{
|
|
|
|
|
if (PtrHolder* p = dynamic_cast<PtrHolder*>(userDataContainer->getUserObject(i)))
|
|
|
|
|
ptrHolder = p;
|
|
|
|
|
{
|
|
|
|
|
if (std::find(ignoreList.begin(), ignoreList.end(), p->mPtr) == ignoreList.end())
|
|
|
|
|
{
|
|
|
|
|
ptrHolder = p;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (RefnumMarker* r = dynamic_cast<RefnumMarker*>(userDataContainer->getUserObject(i)))
|
|
|
|
|
{
|
|
|
|
|
refnumMarkers.push_back(r);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1056,21 +1061,113 @@ namespace MWRender
|
|
|
|
|
|| (intersectionIndex >= vertexCounter
|
|
|
|
|
&& intersectionIndex < vertexCounter + refnumMarkers[i]->mNumVertices))
|
|
|
|
|
{
|
|
|
|
|
result.mHitRefnum = refnumMarkers[i]->mRefnum;
|
|
|
|
|
auto it = std::find_if(
|
|
|
|
|
ignoreList.begin(), ignoreList.end(), [target = refnumMarkers[i]->mRefnum](const auto& ptr) {
|
|
|
|
|
return target == ptr.getCellRef().getRefNum();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (it == ignoreList.end())
|
|
|
|
|
{
|
|
|
|
|
result.mHitRefnum = refnumMarkers[i]->mRefnum;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
vertexCounter += refnumMarkers[i]->mNumVertices;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!result.mHitObject.isEmpty() || result.mHitRefnum.isSet())
|
|
|
|
|
{
|
|
|
|
|
result.mHit = true;
|
|
|
|
|
result.mHitPointWorld = intersection.getWorldIntersectPoint();
|
|
|
|
|
result.mHitNormalWorld = intersection.getWorldIntersectNormal();
|
|
|
|
|
result.mRatio = intersection.ratio;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (ignoreList.empty() || intersector->getIntersectionLimit() != osgUtil::LineSegmentIntersector::NO_LIMIT)
|
|
|
|
|
{
|
|
|
|
|
test(intersector->getFirstIntersection());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (const auto& intersection : intersector->getIntersections())
|
|
|
|
|
{
|
|
|
|
|
test(intersection);
|
|
|
|
|
|
|
|
|
|
if (result.mHit)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class IntersectionVisitorWithIgnoreList : public osgUtil::IntersectionVisitor
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
bool skipTransform(osg::Transform& transform)
|
|
|
|
|
{
|
|
|
|
|
if (mContainsPagedRefs)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
osg::UserDataContainer* userDataContainer = transform.getUserDataContainer();
|
|
|
|
|
if (!userDataContainer)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < userDataContainer->getNumUserObjects(); ++i)
|
|
|
|
|
{
|
|
|
|
|
if (PtrHolder* p = dynamic_cast<PtrHolder*>(userDataContainer->getUserObject(i)))
|
|
|
|
|
{
|
|
|
|
|
if (std::find(mIgnoreList.begin(), mIgnoreList.end(), p->mPtr) != mIgnoreList.end())
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void apply(osg::Transform& transform) override
|
|
|
|
|
{
|
|
|
|
|
if (skipTransform(transform))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
osgUtil::IntersectionVisitor::apply(transform);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setIgnoreList(std::span<const MWWorld::Ptr> ignoreList) { mIgnoreList = ignoreList; }
|
|
|
|
|
void setContainsPagedRefs(bool contains) { mContainsPagedRefs = contains; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::span<const MWWorld::Ptr> mIgnoreList;
|
|
|
|
|
bool mContainsPagedRefs = false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
osg::ref_ptr<osgUtil::IntersectionVisitor> RenderingManager::getIntersectionVisitor(
|
|
|
|
|
osgUtil::Intersector* intersector, bool ignorePlayer, bool ignoreActors)
|
|
|
|
|
osgUtil::Intersector* intersector, bool ignorePlayer, bool ignoreActors,
|
|
|
|
|
std::span<const MWWorld::Ptr> ignoreList)
|
|
|
|
|
{
|
|
|
|
|
if (!mIntersectionVisitor)
|
|
|
|
|
mIntersectionVisitor = new osgUtil::IntersectionVisitor;
|
|
|
|
|
mIntersectionVisitor = new IntersectionVisitorWithIgnoreList;
|
|
|
|
|
|
|
|
|
|
mIntersectionVisitor->setIgnoreList(ignoreList);
|
|
|
|
|
mIntersectionVisitor->setContainsPagedRefs(false);
|
|
|
|
|
|
|
|
|
|
MWWorld::Scene* worldScene = MWBase::Environment::get().getWorldScene();
|
|
|
|
|
for (const auto& ptr : ignoreList)
|
|
|
|
|
{
|
|
|
|
|
if (worldScene->isPagedRef(ptr))
|
|
|
|
|
{
|
|
|
|
|
mIntersectionVisitor->setContainsPagedRefs(true);
|
|
|
|
|
intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mIntersectionVisitor->setTraversalNumber(mViewer->getFrameStamp()->getFrameNumber());
|
|
|
|
|
mIntersectionVisitor->setFrameStamp(mViewer->getFrameStamp());
|
|
|
|
@ -1088,16 +1185,16 @@ namespace MWRender
|
|
|
|
|
return mIntersectionVisitor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RenderingManager::RayResult RenderingManager::castRay(
|
|
|
|
|
const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors)
|
|
|
|
|
RenderingManager::RayResult RenderingManager::castRay(const osg::Vec3f& origin, const osg::Vec3f& dest,
|
|
|
|
|
bool ignorePlayer, bool ignoreActors, std::span<const MWWorld::Ptr> ignoreList)
|
|
|
|
|
{
|
|
|
|
|
osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector(
|
|
|
|
|
new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::MODEL, origin, dest));
|
|
|
|
|
intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST);
|
|
|
|
|
|
|
|
|
|
mRootNode->accept(*getIntersectionVisitor(intersector, ignorePlayer, ignoreActors));
|
|
|
|
|
mRootNode->accept(*getIntersectionVisitor(intersector, ignorePlayer, ignoreActors, ignoreList));
|
|
|
|
|
|
|
|
|
|
return getIntersectionResult(intersector);
|
|
|
|
|
return getIntersectionResult(intersector, mIntersectionVisitor, ignoreList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RenderingManager::RayResult RenderingManager::castCameraToViewportRay(
|
|
|
|
@ -1117,7 +1214,7 @@ namespace MWRender
|
|
|
|
|
|
|
|
|
|
mViewer->getCamera()->accept(*getIntersectionVisitor(intersector, ignorePlayer, ignoreActors));
|
|
|
|
|
|
|
|
|
|
return getIntersectionResult(intersector);
|
|
|
|
|
return getIntersectionResult(intersector, mIntersectionVisitor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RenderingManager::updatePtr(const MWWorld::Ptr& old, const MWWorld::Ptr& updated)
|
|
|
|
|